<?php

namespace App\Kuafu\Order\Service;

use App\Kuafu\Activity\Enum\ActivityEnum;
use App\Kuafu\Activity\Model\ActivityModel;
use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Category\Service\CategoryService;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\Common\Service\SeparateService;
use App\Kuafu\Coupon\Enum\CouponEnum;
use App\Kuafu\Coupon\Service\CouponService;
use App\Kuafu\CouponExt\Enum\CouponExtCodeEnum;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\CouponPackage\Enum\CouponPackageEnum;
use App\Kuafu\CouponPackage\Model\CouponPackageOrderModel;
use App\Kuafu\Customer\Model\CustomerModel;
use App\Kuafu\CustomerCoupon\Model\CustomerCouponModel;
use App\Kuafu\CustomPayment\Model\CustomPaymentModel;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Enum\CodeEnum as OrderEnum;
use App\Kuafu\Order\Enum\OrderCodeEnum;
use App\Kuafu\Order\Enum\OrderInfoEnum;
use App\Kuafu\Order\Exceptions\OrderException;
use App\Kuafu\Order\Model\Clickhouse\OrderCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderCouponCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderCouponExtCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderDiscountCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderPayUnionCHModel;
use App\Kuafu\Order\Model\ConsumerOrder;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderDetailSplitModel;
use App\Kuafu\Order\Model\OrderDiscountSplitModel;
use App\Kuafu\Order\Model\OrderExternalSplitModel;
use App\Kuafu\Order\Model\OrderModel;
use App\Kuafu\Order\Model\OrderOperateRecordModel;
use App\Kuafu\Order\Model\OrderPayUnionSplitModel;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Pay\BasePay;
use App\Kuafu\Pay\Enum\PayCodeEnum;
use App\Kuafu\Pay\Exceptions\PayException;
use App\Kuafu\Pay\Model\Clickhouse\PayStreamCHModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\Shop\Enum\ShopCodeEnum;
use App\Kuafu\Shop\Exceptions\ShopException;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\User\Service\AuthService;
use App\Kuafu\WaiMai\Enum\WaiMaiCodeEnum;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Exceptions\WaiMaiException;
use App\Kuafu\WaiMai\Model\Clickhouse\WaiMaiOrderCHModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use PHP_CodeSniffer\Reports\Code;

class OrderService extends BaseService
{
    /**
     * 根据订单详情获取接口
     *
     * @param $shopId
     * @param $orderId
     * @param array $orderFiled
     * @param array $detailField
     * @param array $couponField
     * @param array $discountField
     * @param array $orderCouponField
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public static function getOrderById(
        $shopId,
        $orderId,
        $orderFiled = [],
        $detailField = [],
        $couponField = [],
        $discountField = [],
        $orderCouponField = [],
        $customerField = []
    ) {
        $detailField      = $detailField ?: OrderInfoEnum::ORDER_DETAIL_DEFAULT_FIELD;
        $orderFiled       = $orderFiled ?: OrderInfoEnum::ORDER_DEFAULT_FIELD;
        $couponField      = $couponField ?: OrderInfoEnum::ORDER_COUPON_EXT_DEFAULT_FIELD;
        $discountField    = $discountField ?: OrderInfoEnum::ORDER_DEFAULT_DISCOUNT_FIELD;
        $orderCouponField = $orderCouponField ?: OrderInfoEnum::ORDER_COUPON_DEFAULT_FIELD;
        $customerField    = $customerField ?: OrderInfoEnum::ORDER_CUSTOMER_DEFAULT_FIELD;

        $model = OrderSplitModel::suffix($shopId);

        $data = $model->getOrderDetailByOrderId(
            $orderId,
            $orderFiled,
            $detailField,
            $couponField,
            $discountField,
            $orderCouponField
        );

        if (!empty($data)) {
            $customerInfo = [
                'name'      => '',
                'mobile'    => '',
                'encMobile' => '',
            ];

            if (!empty($customerField) && $data->userId != 0) {
                $userInfo = CustomerModel::query()->select(['name', 'mobile'])->where('id', $data->userId)
                                         ->first();
                if (!empty($userInfo)) {
                    $userInfo->encMobile = substr($userInfo->mobile ?? '', -4);
                    $customerInfo        = [
                        'name'      => $userInfo->name ?? '',
                        'mobile'    => $userInfo->mobile ?? '',
                        'encMobile' => substr($userInfo->mobile ?? '', -4)
                    ];
                }
            }
            $data->customerInfo = (object)$customerInfo;
        }

        return $data;
    }

    public static function getOrderByIdAfterChange(
        $shopId,
        $orderId,
        $orderFiled = [],
        $detailField = [],
        $couponField = [],
        $discountField = [],
        $orderCouponField = []
    ) {
        $data = self::getOrderById($shopId,
            $orderId,
            $orderFiled,
            $detailField,
            $couponField,
            $discountField,
            $orderCouponField,
        );

        if (!$data) {
            throw new OrderException(OrderCodeEnum::ERR_ORDER_NOT_EXIST);
        }

        return self::dateToChange($data);
    }

    public static function getOrderByIdAfterChangeNew(
        $shopId,
        $orderId,
        $orderFiled = [],
        $detailField = [],
        $couponField = [],
        $discountField = [],
        $orderCouponField = []
    ) {
        $data = self::getOrderById($shopId,
            $orderId,
            $orderFiled,
            $detailField,
            $couponField,
            $discountField,
            $orderCouponField,
        );

        if (!$data) {
            throw new OrderException(OrderCodeEnum::ERR_ORDER_NOT_EXIST);
        }

        return self::dateToChangeNew($data);
    }

    public static function getUserOrderDetailByOrderId(
        $shopId,
        $userId,
        $orderId,
        $orderField,
        $detailField,
        $couponField
    ) {
        return OrderSplitModel::suffix($shopId)
                              ->getUserOrderDetailByOrderId($userId, $orderId, $orderField, $detailField, $couponField);
    }

    public static function getOrderDetailList(
        int $shopId,
        array $where,
        array $field,
        int $pageSize = 10,
        int $pageNum = 1
    ) {
        $queryList = OrderSplitModel::suffix($shopId)
                                    ->getDataPage($where['completeTimeStart'], $where['completeTimeEnd'], 0, $pageSize,
                                        $pageNum,
                                        $field,
                                        '', '', 1, $shopId, CodeEnum::ORDER_STATUS_FINISHED, true);


        $list = [];
        foreach ($queryList->items() as $item) {

            $itemArr = $item->toArray();

            $itemArr['orderId'] = (string)$itemArr['orderId'];

            foreach ($itemArr['order_detail_rel'] as &$detail) {
                $detail['id']              = (string)$detail['id'];
                $detail['orderId']         = (string)$detail['orderId'];
                $detail['packageDetailId'] = (string)$detail['packageDetailId'];
            }

            $itemArr['orderDetail'] = $itemArr['order_detail_rel'] ?? [];

            unset($detail);
            unset($itemArr['order_detail_rel']);

            $list[] = $itemArr;
        }
        return [
            'pageNum'  => $queryList->currentPage(),
            'pageSize' => $queryList->perPage(),
            'count'    => $queryList->total(),
            'lists'    => $list,
        ];
    }

    public static function orderDetailDataToChange($orderInfo)
    {

        $orderUserInfoRel = [];
        if ($orderInfo->isSelfDelivery || $orderInfo->deliveryType > 0) {
            $orderUserInfoRel = $orderInfo->orderUserInfoRel;
        }

        $orderInfo                    = $orderInfo->toArray();
        $cancelTime                   = strtotime($orderInfo['createdAt']) + CodeEnum::ORDER_CANCEL_TIME_MINUS * 60;
        $orderInfo['cancelOrderTime'] = date('Y-m-d H:i:s', $cancelTime);
        $orderInfo['serialNum']       = str_pad($orderInfo['serialNum'], CodeEnum::ORDER_LEADING_ZERO, "0",
            STR_PAD_LEFT);
        $orderInfo['orderStatusDesc'] = CodeEnum::STATUS_CODE_TEXT[$orderInfo['orderStatus']];
        if ($orderInfo['realPayPrice'] == 0) {
            $orderInfo['orderStatusDesc'] = '已退款';
        }
        $orderInfo['orderId']       = (string)$orderInfo['orderId'];
        $orderInfo['shouldPrice']   = $orderInfo['orderShouldPrice'];
        $orderInfo['orderUserInfo'] = [
            'provinceName' => $orderUserInfoRel['provinceName'] ?? '',
            'cityName'     => $orderUserInfoRel['cityName'] ?? '',
            'countyName'   => $orderUserInfoRel['countyName'] ?? '',
            'detailInfo'   => $orderUserInfoRel['detailInfo'] ?? '',
            'telNumber'    => $orderUserInfoRel['telNumber'] ?? '',
            'userName'     => $orderUserInfoRel['userName'] ?? '',
        ];

        //过滤出主商品信息
        $main                          = self::filterOrderDetails($orderInfo, 'order_detail_rel');
        $orderInfo['order_detail_rel'] = $main;
        unset($orderInfo['order_ext_rel']);
        unset($orderInfo['order_user_info_rel']);
        return $orderInfo;
    }

    public static function filterOrderDetails($orderInfo, $column): array
    {
        $main = collect($orderInfo[$column])->map(function ($item) {
            if ($item['packageDetailId'] != 0) {
                return null;
            }
            return $item;
        })->filter()->toArray();
        //套餐商品
        $package = collect($orderInfo[$column])->map(function ($item) {
            if ($item['packageDetailId'] == 0) {
                return null;
            }
            return $item;
        })->filter()->toArray();
        $main    = array_merge($main);
        if (!empty($package)) {
            foreach ($main as $key => $value) {
                foreach ($package as $k => $v) {
                    if ($v['packageDetailId'] == $value['id']) {
                        $v['num']                    = $v['packageUnitNum'];
                        $main[$key]['packageList'][] = $v;
                    }
                }
            }
        }
        return $main;
    }

    /**
     * 订单详情数据转换
     * @param $data
     * @return mixed
     */
    public static function dateToChange($data)
    {
        $shopInfo = ShopService::getShopInfo($data->shopId);

        $storeOrder                 = clone $data;
        $storeOrder->orderDetailRel = $storeOrder->orderDetailRel->where('type',
            \App\Kuafu\Product\Enum\CodeEnum::PRODUCT_TYPE_SINGLE);
        $storeOrderList             = (new Collection())->push($storeOrder);
        //获取优惠明细
        $discountRows = OrderStatisticsService::getInStoreDiscountData($storeOrderList, $shopInfo);
        //获取支付明细
        $inStorePayStreamRows = OrderStatisticsService::getInStorePayStream($storeOrderList, $shopInfo, true);
        $orderUserInfoRel     = [];
        if ($data->isSelfDelivery || $data->deliveryType > 0) {
            $orderUserInfoRel = $data->orderUserInfoRel;
        }

        $data = $data->toArray();

        //获取支付明细
        $data['payChannelDetail'] = [];
        foreach ($inStorePayStreamRows as $payRow) {
            $data['payChannelDetail'][] = [
                'payType'      => $payRow[3],
                'payDiscount'  => bcmul($payRow[4], 100),
                'payReal'      => bcmul($payRow[5], 100),
                'hasRefund'    => $payRow[10],
                'refundAmount' => is_numeric($payRow[11]) ? bcmul($payRow[11], 100) : $payRow[11],
                'operateUser'  => $payRow[12],
                'payChannelId' => $payRow[13] ?? 0,
                'isPaidIn'     => $payRow[14] ?? 0,
                'payNo'        => $payRow[9] ?? '',
            ];
        }

        //获取优惠明细
        $data['orderDiscountDetail'] = [];
        foreach ($discountRows as $discountRow) {
            $data['orderDiscountDetail'][] = [
                'discountType'   => $discountRow[3],
                'discountName'   => str_replace('：', '  ', $discountRow[4]),
                'discountAmount' => bcmul($discountRow[6], 100),
            ];
        }

        $todayTime                   = strtotime(date("Y-m-d"), time());
        $data['isAllowRefundStatus'] = false;
        if ($data['orderStatus'] == CodeEnum::ORDER_STATUS_FINISHED) {
            $data['isAllowRefundStatus'] = true;
        }
        if ($data['completeTime'] < $todayTime) {
            $data['isAllowRefundStatus'] = false;
        }
        if (count($data['order_coupon_ext_rel']) > 1) {
            $data['isAllowRefundStatus'] = false;
        }
        $data['completeTime']     = $data['completeTime'] == 0 ? '' : date('Y-m-d H:i:s', $data['completeTime']);
        $data['orderDetail']      = $data['order_detail_rel'];
        $data['payChannelDesc']   = CodeEnum::CHANNEL_CODE_TEXT[$data['payChannel']];
        $data['orderStatusDesc']  = CodeEnum::STATUS_CODE_TEXT[$data['orderStatus']];
        $data['refundStatusDesc'] = CodeEnum::REFUND_CODE_TEXT[$data['refundStatus']];
        //categoryIds
        $categoryIds = array_column($data['orderDetail'], 'categoryId');
        //查询分类信息
        $categoryList = CategoryService::getCateListByIds($categoryIds)->keyBy('id')->toArray();
        foreach ($data['orderDetail'] as $k => $v) {
            $res = CommonService::getIsPrintLabelByName($v['productName'], CodeEnum::SOURCE_TYPE_POS);//匹配打印配置

            $data['orderDetail'][$k]['discountTypeDesc'] = CodeEnum::DISCOUNT_TYPE_TEXT[$v['discountType']];
            $data['orderDetail'][$k]['realPrice']        = $v['originalPrice'] - $v['discountPrice'];
            $data['orderDetail'][$k]['categoryName']     = $categoryList[$v['categoryId']]['name'] ?? "";
            $data['orderDetail'][$k]['isPrintLabel']     = $res['isPrintLabel'];//默认0-不打印 1-打印
            $data['orderDetail'][$k]['printLabelType']   = $res['printLabelType'];//默认0-不打印 1-饮品打印 2-非饮品打印
        }
        $data['orderCoupon']   = $data['order_coupon_ext_rel'];
        $data['orderDiscount'] = $data['order_discount_rel'];
        foreach ($data['orderCoupon'] as $key => $value) {
            if ($value['couponExtStatus'] != CouponExtEnum::COUPON_STATUS_USED) {
                unset($data['orderCoupon'][$key]);
                continue;
            }
            $extPlatformDesc                               = CouponExtEnum::EXT_PLATFORM_TEXT[$value['extPlatform']];
            $couponTypeDesc                                = CouponExtEnum::COUPON_TYPE_TEXT[$value['couponExtType']];
            $data['orderCoupon'][$key]['useCouponDesc']    = $extPlatformDesc . '结账-' . $couponTypeDesc . $value['couponExtDiscountPrice'];
            $data['orderCoupon'][$key]['extPlatformDesc']  = $extPlatformDesc;
            $data['orderCoupon'][$key]['couponStatusDesc'] = CouponExtEnum::COUPON_STATUS_TEXT[$value['couponExtStatus']];
            $data['orderCoupon'][$key]['couponTypeDesc']   = $couponTypeDesc;

            $couponExtDataInfo = json_decode($value['couponExtCodeData'], true);
            $useProducts       = null;
            if (!empty($couponExtDataInfo)) {
                $useProducts = $couponExtDataInfo['customData']['useProducts'] ?? null;
            }
            $data['orderCoupon'][$key]['useProducts'] = $useProducts;
        }
        $data['orderCoupon'] = array_values($data['orderCoupon']);
        foreach ($data['orderDiscount'] as $item => $datum) {
            $data['orderDiscount'][$item]['discountTypeDesc'] = CodeEnum::DISCOUNT_TYPE_TEXT[$datum['discountType']];
        }

        $data['orderIdAll'] = $data['orderId'];
        $data['orderId']    = substr($data['orderId'], -8);
        $data['serialNum']  = str_pad($data['serialNum'], CodeEnum::LEADING_ZERO_LENGTH, "0", STR_PAD_LEFT);

        //处理套餐商品
        $main                = self::filterOrderDetails($data, 'orderDetail');
        $data['orderDetail'] = $main;
        $data['count']       = count($data['orderDetail']);
        //处理优惠券
        //获取原始优惠券id列表
        $couponIds = array_column($data['order_coupon_rel'], 'couponId');
        //查询优惠券基本信息
        $field             = ['id', 'discount', 'canUseProduct'];
        $couponListByIds   = CouponService::getCouponListByIds($couponIds, $field);
        $couponListByIdsBy = array_column($couponListByIds, null, 'id');
        foreach ($data['order_coupon_rel'] as $key => $value) {
            if (isset($couponListByIdsBy[$value['couponId']])) {
                $data['order_coupon_rel'][$key]['discount'] = $couponListByIdsBy[$value['couponId']]['discount'];
            } else {
                $data['order_coupon_rel'][$key]['discount'] = 0;
            }

            if ($value['couponType'] == CouponEnum::COUPON_TYPE_EXCHANGE) {
                $data['order_coupon_rel'][$key]['discount'] = $data['order_coupon_rel'][$key]['couponDiscountPrice'];
            }
            $data['order_coupon_rel'][$key]['canUseProduct'] = $couponListByIdsBy[$value['couponId']]['canUseProduct'] ?? "";

            if (!empty($data['order_coupon_rel'][$key]['customer_coupon_rel']['couponCode'])) {
                $data['order_coupon_rel'][$key]['couponCode']   = $data['order_coupon_rel'][$key]['customer_coupon_rel']['couponCode'];
                $data['order_coupon_rel'][$key]['cappedAmount'] = $data['order_coupon_rel'][$key]['customer_coupon_rel']['cappedAmount'];
                unset($data['order_coupon_rel'][$key]['customer_coupon_rel']);
            }

            $data['order_coupon_rel'][$key]['useProducts'] = null;
            if (!empty($data['order_coupon_rel'][$key]['canUseProduct'])) {
                $data['order_coupon_rel'][$key]['useProducts']['list'] = [[
                    'canUseProduct' => $data['order_coupon_rel'][$key]['canUseProduct'],
                    'productLimit' => 1
                ]];
            }


        }
        $data['orderCouponRel'] = $data['order_coupon_rel'];

        $data['invoiceInfo'] = [
            'invoiceStatusOut'      => OrderInvoiceService::orderInvoiceStatus(
                $data['invoiceStatus'], $storeOrder['completeTime'], $storeOrder['invoiceCanCancelCount']),
            'invoiceUrl'            => $storeOrder['realPayPrice'] > 0 ? OrderInvoiceService::genOrderInvoiceUrl($data['orderIdAll'],
                $data['invoiceStatus'], $data['shopId']) : '',
            'invoiceCanCancelCount' => $storeOrder['invoiceCanCancelCount']
        ];

        $data['orderUserInfo'] = [
            'provinceName' => (string)($orderUserInfoRel['provinceName'] ?? ''),
            'cityName'     => (string)($orderUserInfoRel['cityName'] ?? ''),
            'countyName'   => (string)($orderUserInfoRel['countyName'] ?? ''),
            'detailInfo'   => (string)($orderUserInfoRel['detailInfo'] ?? ''),
            'telNumber'    => (string)($orderUserInfoRel['telNumber'] ?? ''),
            'userName'     => (string)($orderUserInfoRel['userName'] ?? ''),
        ];

        unset($data['order_detail_rel']);
        unset($data['order_coupon_ext_rel']);
        unset($data['order_discount_rel']);
        unset($data['order_user_info_rel']);
        return $data;
    }

    public static function dateToChangeNew($data)
    {
        $shopInfo                   = ShopService::getShopInfo($data->shopId);
        $storeOrder                 = clone $data;
        $storeOrder->orderDetailRel = $storeOrder->orderDetailRel->where('type',
            \App\Kuafu\Product\Enum\CodeEnum::PRODUCT_TYPE_SINGLE);
        $storeOrderList             = (new Collection())->push($storeOrder);
        //获取优惠明细
        $discountRows = OrderStatisticsService::getInStoreDiscountData($storeOrderList, $shopInfo, true);
        //获取支付明细
        $inStorePayStreamRows = OrderStatisticsService::getInStorePayStream($storeOrderList, $shopInfo, true);

        $orderUserInfoRel = [];
        if ($data->isSelfDelivery || $data->deliveryType > 0) {
            $orderUserInfoRel = $data->orderUserInfoRel;
        }

        $data = $data->toArray();
        //获取支付明细
        $data['totalPayment']  = [];//支付合计
        $data['orderReceived'] = []; //订单实收
        $totalPayment          = 0;
        $totalOrderReceived    = 0;
        foreach ($inStorePayStreamRows as $payRow) {
            $refundMoney  = is_numeric($payRow[11]) ? $payRow[11] : 0;
            $totalPayment = bcadd($totalPayment, bcsub($payRow[16], $refundMoney, 2), 2);
            if ($payRow[16] - $refundMoney > 0) {
                array_push($data['totalPayment'], [
                    'payName'      => $payRow[3],
                    'payPrice'     => bcmul($payRow[16], 100) - bcmul($refundMoney, 100),
                    'refundAmount' => $refundMoney,
                ]);
            }
            if ($payRow[15] == CodeEnum::ORDER_INFO_PAY_TYPE_REAL) {
                if ($payRow[14] == 1) {
                    $totalOrderReceived += $payRow[5] - $refundMoney;
                    if ($payRow[5] - $refundMoney > 0) {
                        array_push($data['orderReceived'], [
                            'payName'      => $payRow[3],
                            'payPrice'     => bcmul($payRow[5], 100) - bcmul($refundMoney, 100),
                            'refundAmount' => $refundMoney,
                        ]);
                    }
                }
            }
        }
        $data['totalPayment']  = [
            'total' => bcmul($totalPayment, 100),
            'list'  => $data['totalPayment']
        ];
        $data['orderReceived'] = [
            'total' => bcmul($totalOrderReceived, 100),
            'list'  => $data['orderReceived']
        ];
        //获取优惠明细
        $data['paymentPreference'] = [];//支付优惠
        $data['orderCouponNew']    = []; //订单优惠
        $totalPaymentPreference    = 0;
        $totalOrderCouponNew       = 0;
        foreach ($discountRows as $discountRow) {
            if ($discountRow[8] == CodeEnum::ORDER_INFO_COUPON_TYPE_PAY) {
                $totalPaymentPreference += $discountRow[6];
                array_push($data['paymentPreference'], [
                    'discountName'   => str_replace('：', '  ', $discountRow[4]),
                    'discountAmount' => bcmul($discountRow[6], 100),
                ]);
            } else {
                if ($discountRow[9] == 0) {
                    $totalOrderCouponNew += $discountRow[6];
                }
                array_push($data['orderCouponNew'], [
                    'discountName'   => str_replace('：', '  ', $discountRow[4]),
                    'discountAmount' => bcmul($discountRow[6], 100),
                ]);
            }
        }
        $data['paymentPreference']   = [
            'total' => bcmul($totalPaymentPreference, 100),
            'list'  => $data['paymentPreference']
        ];
        $data['orderCouponNew']      = [
            'total' => bcmul($totalOrderCouponNew, 100),
            'list'  => $data['orderCouponNew']
        ];
        $todayTime                   = strtotime(date("Y-m-d"), time());
        $data['isAllowRefundStatus'] = false;
        if ($data['orderStatus'] == CodeEnum::ORDER_STATUS_FINISHED) {
            $data['isAllowRefundStatus'] = true;
        }
        if ($data['completeTime'] < $todayTime) {
            $data['isAllowRefundStatus'] = false;
        }
        if (count($data['order_coupon_ext_rel']) > 1) {
            $data['isAllowRefundStatus'] = false;
        }
        $data['completeTime'] = $data['completeTime'] == 0 ? '' : date('Y-m-d H:i:s', $data['completeTime']);
        $data['orderDetail']  = $data['order_detail_rel'];
//        $data['payChannelDesc']   = CodeEnum::CHANNEL_CODE_TEXT[$data['payChannel']];
        $data['payChannelDesc']   = '';
        $data['orderStatusDesc']  = CodeEnum::STATUS_CODE_TEXT[$data['orderStatus']];
        $data['refundStatusDesc'] = CodeEnum::REFUND_CODE_TEXT[$data['refundStatus']];
        //categoryIds
        $categoryIds = array_column($data['orderDetail'], 'categoryId');
        //查询分类信息
        $categoryList = CategoryService::getCateListByIds($categoryIds)->keyBy('id')->toArray();
        foreach ($data['orderDetail'] as $k => $v) {
            $res = CommonService::getIsPrintLabelByName($v['productName'], CodeEnum::SOURCE_TYPE_POS);// 匹配打印配置

            $data['orderDetail'][$k]['discountTypeDesc'] = CodeEnum::DISCOUNT_TYPE_TEXT[$v['discountType']];
            $data['orderDetail'][$k]['realPrice']        = $v['originalPrice'] - $v['discountPrice'];
            $data['orderDetail'][$k]['categoryName']     = $categoryList[$v['categoryId']]['name'] ?? "";
            $data['orderDetail'][$k]['isPrintLabel']     = $res['isPrintLabel'];// 默认0-不打印 1-打印
            $data['orderDetail'][$k]['printLabelType']   = $res['printLabelType'];// 默认0-不打印 1-饮品打印 2-非饮品打印
        }
        $data['orderCoupon']   = $data['order_coupon_ext_rel'];
        $data['orderDiscount'] = $data['order_discount_rel'];
        foreach ($data['orderCoupon'] as $key => $value) {
            if ($value['couponExtStatus'] != CouponExtEnum::COUPON_STATUS_USED) {
                unset($data['orderCoupon'][$key]);
                continue;
            }
            unset($data['orderCoupon'][$key]['couponExtCodeData']);
            $extPlatformDesc                               = CouponExtEnum::EXT_PLATFORM_TEXT[$value['extPlatform']];
            $couponTypeDesc                                = CouponExtEnum::COUPON_TYPE_TEXT[$value['couponExtType']];
            $data['orderCoupon'][$key]['useCouponDesc']    = $extPlatformDesc . '结账-' . $couponTypeDesc . $value['couponExtDiscountPrice'];
            $data['orderCoupon'][$key]['extPlatformDesc']  = $extPlatformDesc;
            $data['orderCoupon'][$key]['couponStatusDesc'] = CouponExtEnum::COUPON_STATUS_TEXT[$value['couponExtStatus']];
            $data['orderCoupon'][$key]['couponTypeDesc']   = $couponTypeDesc;

            $couponExtDataInfo = json_decode($value['couponExtCodeData'], true);
            $canUseProduct     = '';
            $canUseProducts    = null;
            if (!empty($couponExtDataInfo)) {
                $canUseProduct  = $couponExtDataInfo['canUseProduct'] ?? '';
                $canUseProducts = $couponExtDataInfo['canUseProducts'] ?? null;
            }
            $data['orderCoupon'][$key]['canUseProduct']  = $canUseProduct;
            $data['orderCoupon'][$key]['canUseProducts'] = $canUseProducts;
        }
        $data['orderCoupon'] = array_values($data['orderCoupon']);
        foreach ($data['orderDiscount'] as $item => $datum) {
            $data['orderDiscount'][$item]['discountTypeDesc'] = CodeEnum::DISCOUNT_TYPE_TEXT[$datum['discountType']];
        }

        $data['orderIdAll'] = $data['orderId'];
        $data['orderId']    = substr($data['orderId'], -8);
        $data['serialNum']  = str_pad($data['serialNum'], CodeEnum::LEADING_ZERO_LENGTH, "0", STR_PAD_LEFT);

        //处理套餐商品
        $main                = self::filterOrderDetails($data, 'orderDetail');
        $data['orderDetail'] = $main;
        $data['count']       = count($data['orderDetail']);
        //处理优惠券
        //获取原始优惠券id列表
        $couponIds = array_column($data['order_coupon_rel'], 'couponId');
        //查询优惠券基本信息
        $field             = ['id', 'discount'];
        $couponListByIds   = CouponService::getCouponListByIds($couponIds, $field);
        $couponListByIdsBy = array_column($couponListByIds, null, 'id');
        foreach ($data['order_coupon_rel'] as $key => $value) {
            if (isset($couponListByIdsBy[$value['couponId']])) {
                $data['order_coupon_rel'][$key]['discount'] = $couponListByIdsBy[$value['couponId']]['discount'];
            } else {
                $data['order_coupon_rel'][$key]['discount'] = 0;
            }
        }
        $data['orderCouponRel'] = $data['order_coupon_rel'];

        $data['invoiceInfo'] = [
            'invoiceStatusOut'      => OrderInvoiceService::orderInvoiceStatus($data['invoiceStatus'],
                $storeOrder['completeTime'], $storeOrder['invoiceCanCancelCount']),
            'invoiceUrl'            => $storeOrder['realPayPrice'] > 0 ? OrderInvoiceService::genOrderInvoiceUrl($data['orderIdAll'],
                $data['invoiceStatus'], $data['shopId']) : '',
            'invoiceCanCancelCount' => $storeOrder['invoiceCanCancelCount']
        ];


        $data['orderUserInfo'] = [
            'provinceName' => (string)($orderUserInfoRel['provinceName'] ?? ''),
            'cityName'     => (string)($orderUserInfoRel['cityName'] ?? ''),
            'countyName'   => (string)($orderUserInfoRel['countyName'] ?? ''),
            'detailInfo'   => (string)($orderUserInfoRel['detailInfo'] ?? ''),
            'telNumber'    => (string)($orderUserInfoRel['telNumber'] ?? ''),
            'userName'     => (string)($orderUserInfoRel['userName'] ?? ''),
        ];

        unset($data['order_detail_rel']);
        unset($data['order_coupon_ext_rel']);
        unset($data['order_discount_rel']);
        unset($data['order_user_info_rel']);

        return $data;
    }

    public static function getOrderList(
        $completeTimeStart,
        $completeTimeEnd,
        $serialNum,
        $pageSize,
        $pageNum,
        $field,
        $orderColumn,
        $orderType,
        $brandId,
        $shopId,
        $orderStatus
    ): array {
        $query = OrderSplitModel::suffix($shopId)
                                ->getDataPage($completeTimeStart, $completeTimeEnd, $serialNum, $pageSize, $pageNum,
                                    $field,
                                    $orderColumn, $orderType, $brandId, $shopId, $orderStatus);
        $count = self::sumMoney(OrderSplitModel::suffix($shopId)
                                               ->getOrderPriceCount($completeTimeStart, $completeTimeEnd, $shopId,
                                                   $brandId, $orderStatus, $serialNum));
        //聚合订单orderId列表
        $orderIds = array_column($query->items(), 'orderId');
        //查询订单优惠券
        $couponField  = ['orderId', 'extPlatform', 'couponExtDiscountPrice', 'couponExtType'];
        $orderCoupons = OrderCouponExtSplitModel::suffix($shopId)->getListByOrderIds($orderIds, $couponField);
        $couponList   = [];
        //计算代金券
        foreach ($orderCoupons->toArray() as $v) {
            if (isset($couponList[$v['orderId']])) {
                $couponList[$v['orderId']]['couponExtDiscountPrice'] += $v['couponExtDiscountPrice'];
            } else {
                $couponList[$v['orderId']] = $v;
            }
        }
        self::changeOrderListToDate('completeTime', $query->items(), $couponList);


        foreach ($query->items() as &$item) {
            $item['invoiceStatusOut'] = OrderInvoiceService::orderInvoiceStatus($item['invoiceStatus'],
                $item['createdAt']->timestamp, $item['invoiceCanCancelCount']);
        }

        return [
            'pageNum'            => $query->currentPage(),
            'pageSize'           => $query->perPage(),
            'count'              => $query->total(),
            'totalOriginalPrice' => $count['totalOriginalPrice'],
            'totalShouldPrice'   => $count['totalShouldPrice'],
            'totalDiscountPrice' => $count['totalDiscountPrice'],
            'totalPayPrice'      => $count['totalPayPrice'],
            'totalTypePrice'     => $count['totalTypePrice'],
            'lists'              => $query->items(),
        ];
    }

    /**
     * $num / 100
     */
    public static function bcDiv($num, $func = 'floor')
    {
        // 向下取整
        $result = $func(bcdiv($num, 100, 2));
        return $result;
    }

    /**
     * 获取取整方式
     *
     * @param $shopId
     * @return int
     */
    public static function getInterMethod($shopId): int
    {
        // 后期改成配置/数据库读取
        return CodeEnum::ORDER_INTER_METHOD_FLOOR;
    }

    /**
     * 取整函数
     *
     * @param $shopId
     * @param $num
     * @return int
     */
    public static function calcInter($shopId, $num): int
    {
        $method = self::getInterMethod($shopId);

        switch ($method) {
            case CodeEnum::ORDER_INTER_METHOD_FLOOR:
                $retNum = floor($num);
                break;
            case CodeEnum::ORDER_INTER_METHOD_CEIL:
                $retNum = ceil($num);
                break;
            case CodeEnum::ORDER_INTER_METHOD_DEFAULT:
            default:
                $retNum = round($num);
        }

        return (int)$retNum;

    }


    /**
     * 订单详情数据转换
     * @param $column
     * @param $data
     * @return array
     */
    public static function changeOrderListToDate($column, $data, $couponList): array
    {
        foreach ($data as $k => $v) {
            $data[$k]['useCouponDesc'] = '';
            if (isset($couponList[$v['orderId']]) && $couponList[$v['orderId']]['couponExtDiscountPrice'] > 0) {
                $extPlatformDesc           = CouponExtEnum::EXT_PLATFORM_TEXT[$couponList[$v['orderId']]['extPlatform']];
                $couponTypeDesc            = CouponExtEnum::COUPON_TYPE_TEXT[$couponList[$v['orderId']]['couponExtType']];
                $data[$k]['useCouponDesc'] = $extPlatformDesc . '结账-' . $couponTypeDesc . ":" . $couponList[$v['orderId']]['couponExtDiscountPrice'];
            }
            $data[$k][$column]            = $v[$column] == 0 ? 0 : date("Y-m-d H:i:s", $v[$column]);
            $data[$k]['serialNum']        = str_pad($v['serialNum'], CodeEnum::LEADING_ZERO_LENGTH, "0", STR_PAD_LEFT);
            $data[$k]['orderIdAll']       = $v['orderId'];
            $data[$k]['orderId']          = substr($v['orderId'], -8);
            $data[$k]['payChannelDesc']   = CodeEnum::CHANNEL_CODE_TEXT[$v['payChannel']];
            $data[$k]['refundStatusDesc'] = CodeEnum::REFUND_CODE_TEXT[$v['refundStatus']];
            $data[$k]['orderStatusDesc']  = CodeEnum::STATUS_CODE_TEXT[$v['orderStatus']];
        }
        return $data;
    }

    /**
     * 校验订单是否存在
     *
     * @return bool
     */
    public static function checkOrderIsExist($shopId, $orderId): bool
    {
        $order = OrderSplitModel::suffix($shopId)
                                ->where('shopId', $shopId)
                                ->where('orderId', $orderId)
                                ->first();
        return empty($order);
    }

    public static function checkOffOrderIsExist($shopId, $orderId): bool
    {
        $order = OrderSplitModel::suffix($shopId)
                                ->where('shopId', $shopId)
                                ->where('offOrderId', $orderId)
                                ->first();


        return empty($order);
    }

    public static function sumMoney($data): array
    {
        $totalOriginalPrice = 0;
        $totalShouldPrice   = 0;
        $totalDiscountPrice = 0;
        $totalPayPrice      = 0;
        foreach ($data as $v) {
            $totalOriginalPrice += $v['originalPrice'];
            $totalShouldPrice   += $v['shouldPrice'];
            $totalDiscountPrice += $v['realDiscountPrice'];
            $totalPayPrice      += $v['realPayPrice'];
        }
        return [
            'totalOriginalPrice' => $totalOriginalPrice,
            'totalShouldPrice'   => $totalShouldPrice,
            'totalDiscountPrice' => $totalDiscountPrice,
            'totalPayPrice'      => $totalPayPrice,
            'totalTypePrice'     => $totalPayPrice,
        ];
    }

    /**
     * 获取订单列表
     *
     * @param $userId
     * @param $pageSize
     * @param $pageNum
     * @param $shopId
     * @param int $flagComplain
     * @return array
     */
    public static function getUserOrderList(
        $userId,
        $pageSize,
        $pageNum,
        $shopId,
        $flagComplain = CodeEnum::ORDER_STATUS_DEFAULT
    ) {
        $orderLists = OrderSplitModel::suffix($shopId)->getUserOrderList($userId, $pageSize, $pageNum, $flagComplain);
        $orderList  = $orderLists->items();
        //查询店铺信息
        $shopIds  = array_unique(array_column($orderList, 'shopId'));
        $shopList = ShopService::getShopListByShopIds($shopIds);
        $shopList = $shopList->keyBy("id")->toArray();
        //查询订单详情
        $orderIds         = array_column($orderList, 'orderId');
        $orderDetailsList = OrderDetailSplitModel::suffix($shopId)::getListByOrderIds($orderIds);
        $result           = array();
        foreach ($orderDetailsList as $k => $info) {
            $result[$info['orderId']][$k]             = $info->toArray();
            $result[$info['orderId']][$k]['imageUrl'] = CommonService::joinImageUrl($info['imageUrl']);
        }

        //组装数据
        $returnData = [];
        foreach ($orderList as $key => $value) {
            if (empty($result[$value['orderId']])) {
                continue;
            }
            $returnData[$key]['orderId']     = (string)$value['orderId'];
            $returnData[$key]['createdAt']   = $value['createdAt']->toDateTimeString();
            $returnData[$key]['orderStatus'] = CodeEnum::STATUS_CODE_TEXT[$value['orderStatus'] ?: 0];
            if ($value['orderStatus'] == CodeEnum::ORDER_STATUS_REVERSE) {
                $returnData[$key]['orderStatus'] = CodeEnum::STATUS_CODE_TEXT[CodeEnum::ORDER_STATUS_FINISHED];
            }
            $returnData[$key]['shopName']    = $shopList[$value['shopId']]['name'];
            $returnData[$key]['shortName']   = $shopList[$value['shopId']]['shortName'] ?? "";
            $returnData[$key]['payPrice']    = $value['payPrice'];
            $returnData[$key]['shouldPrice'] = $value['orderShouldPrice'];
            $returnData[$key]['count']       = count($result[$value['orderId']]);
            $returnData[$key]['orderList']   = array_slice($result[$value['orderId']], 0, 3);
        }
        $return['pageNum']  = $orderLists->currentPage();
        $return['pageSize'] = $orderLists->perPage();
        $return['count']    = $orderLists->total();
        $return['list']     = array_values($returnData);
        return $return;
    }

    public static function getUserOrderFieldByOrderId($userId, $orderId, $filed, $shopId)
    {
        return OrderSplitModel::suffix($shopId)->getUserOrderFieldByOrderId($userId, $orderId, $filed);
    }

    public static function getOrderFieldByOrderId($orderId, $filed, $shopId)
    {
        return OrderSplitModel::suffix($shopId)->getOrderFieldByOrderId($orderId, $filed);
    }

    /**
     * 店铺的日结单统计
     * https://pms.51kuafu.com/index.php?m=story&f=view&storyID=19
     *
     * @param int $shopId
     * @param int $startTime
     * @param int $endTime
     * @return array
     * @throws ShopException
     */
    public static function sCalcShopTrade(int $shopId, int $startTime, int $endTime): array
    {
        ini_set("memory_limit", "300M");

        //  店铺信息
        $shop = ShopService::getShopInfo($shopId);
        if (!$shop) {
            throw new ShopException(ShopCodeEnum::ERR_SHOP_ID_NO_EXIST);
        }

        try {
            $printUserName = AuthService::getAuthUser()['username'] ?? '';
        } catch (\Exception $e) {
            $printUserName = '';
        }

        //门店订单统计
        $shopOrderStatistical = self::shopOrderStatistical($shopId, $startTime, $endTime);
        $normalOrderIds       = $shopOrderStatistical->normalOrderNums;
        //门店外卖订单统计
        $shopTakeOutOrderStatistical = self::shopTakeOutOrderStatistical($shopId, $startTime, $endTime);
        //第三方优惠券统计
        $shopOrderCouponExtStatistical = self::shopOrderCouponExtStatistical($shopId, $startTime, $endTime);
        //订单详情统计
        $shopOrderDetailStatistical = self::shopOrderDetailStatistical($shopId, $startTime, $endTime, $normalOrderIds);
        //门店优惠券使用统计
        $shopCouponStatistical = self::shopCouponStatistical($shopId, $startTime, $endTime);
        //流水统计
        $shopPayStreamStatistical = self::shopPayStreamStatistical($shopId, $startTime, $endTime, $normalOrderIds);
        //订单折扣统计
        $shopOrderDiscountStatistical = self::shopOrderDiscountStatistical(
            $shopId, $startTime, $endTime, $shopOrderDetailStatistical, $normalOrderIds
        );

        //todo 满赠活动统计
        $shopGiftActivityStatistical = self::shopGiftActivityStatistical($shopId, $normalOrderIds);

        //券包销售统计
        $shopCouponPackageStatistical = self::shopCouponPackageStatistical($shopId, $startTime, $endTime);

        //首款合计修正
        $shopPayStreamStatistical->total['sum'] +=
            $shopTakeOutOrderStatistical->all['sum'] //外卖收益
            + $shopCouponStatistical->shopCoupon['sum'] //门店券
            + $shopOrderCouponExtStatistical->mt['sum']//美团
            + $shopOrderCouponExtStatistical->dy['sum'];//抖音

        $engine = (new SeparateService($startTime, $endTime))->check();
        if ($engine == SeparateService::DB) {
            $orderModel       = OrderSplitModel::suffix($shopId);
            $waimaiOrderModel = WaiMaiOrderModel::suffix($shopId);
        } else {
            $orderModel       = OrderCHModel::query();
            $waimaiOrderModel = WaiMaiOrderCHModel::query();
        }

        $monthTotal = (
        ($orderModel
                ->whereBetween('createdAt',
                    [strtotime(date('Ym01', $endTime)), $endTime])
                ->where('shopId', $shopId)
                ->where('orderStatus', OrderEnum::ORDER_STATUS_FINISHED)
                ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL)
                ->sum('realPayPrice') ?? 0)
            + ($waimaiOrderModel
                ->whereBetween('createdAt',
                    [strtotime(date('Ym01', $endTime)), $endTime])
                ->where('shopId', $shopId)
                ->where('orderStatus', '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                ->sum('expectIncome') ?? 0)
            + CouponPackageOrderModel::query()
                                     ->whereBetween('createdAt', [strtotime(date('Ym01', $endTime)), $endTime])
                                     ->where('shopId', $shopId)
                                     ->where('payStatus', CouponPackageEnum::PAY_STATUS_ON)
                                     ->sum('payPrice')
        );

        $data = [
            //门店信息
            'shop'                         => [
                'shopCode'      => str_pad($shop->shopCode, ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0",
                    STR_PAD_LEFT),
                'name'          => $shop->name,
                'startTime'     => date('Y-m-d H:i', $startTime),
                'endTime'       => date('Y-m-d H:i', $endTime),
                'printTime'     => date('Y-m-d H:i'),
                'printUserName' => $printUserName,
            ],
            //门店券包销售统计
            'shopCouponPackageStatistical' => $shopCouponPackageStatistical->shopCouponPackageSale,
            //堂食营业指标
            'eatInStatistical'             => $shopOrderStatistical->eatInStatistical,
            //外卖营业指标1
            'takeOutStatistical'           => $shopTakeOutOrderStatistical->all,
            // 营业指标
            'order'                        => [
                // 订单笔数 门店POS+扫码点餐+外卖有效+券包销售订单量
                'count'               => (int)
                ($shopOrderStatistical->ct + $shopTakeOutOrderStatistical->all['count'] + $shopCouponPackageStatistical->shopCouponPackageSale['count']),
                // 订单原价合计 外卖单菜品原价合计+堂食原价合计+券包原价合计
                'originPrice'         => (int)
                (
                    $shopOrderStatistical->sumOriginalPrice +
                    $shopTakeOutOrderStatistical->all['sumOriginalPrice'] +
                    $shopCouponPackageStatistical->shopCouponPackageSale['sum']
//                     + $shopTakeOutOrderStatistical->all['sumPackingPrice']
                ),
                // 订单优惠合计；逻辑同综合报表统计。堂食优惠金额+外卖优惠金额+券包优惠金额合计
                'discountPrice'       => (int)
                ($shopOrderStatistical->sumDiscountPrice + $shopTakeOutOrderStatistical->all['sumDiscount']),
                // 退款 堂食+外卖退款合计（取实际退还到顾客账户上的金额），券包无退款
                'refundPrice'         => (int)
                ($shopOrderStatistical->sumRefundMoney + $shopTakeOutOrderStatistical->all['sumRefundPrice']),
                // 营业收入合计 堂食实收+外卖实收+券包实收  对应
                'payPrice'            => (int)
                (
                    $shopOrderStatistical->sumPayPrice + $shopTakeOutOrderStatistical->all['sumPayPrice'] + $shopCouponPackageStatistical->shopCouponPackageSale['sum']
                    - $shopOrderStatistical->sumRefundMoney - $shopTakeOutOrderStatistical->all['sumRefundPrice']
                ),
                // 试吃合计
                'foretaste'           => (int)$shopPayStreamStatistical->foretaste,
                // 外卖平台服务费
                'waiMaiPlatformPrice' => (int)$shopTakeOutOrderStatistical->all['sumPlatformPrice'],
                // 订单实收=微信+支付宝+美团+现金, 在下面重写
                'orderAccept'         => (int)($shopOrderStatistical->sumRealPayMoney + $shopTakeOutOrderStatistical->all['sum']),
            ],
            // 营业收款构成
            'pay'                          => [
                'totalAccept'   => $shopPayStreamStatistical->total,  // 收款合计；含实际收入渠道包括现金和扫码支付的所有渠道
                'cash'          => $shopPayStreamStatistical->cash, // 现金
                'scanPay'       => $shopPayStreamStatistical->scanPay, // 扫码支付
                'meiTuan'       => $shopOrderCouponExtStatistical->mt,
                'dy'            => $shopOrderCouponExtStatistical->dy,
                'xhs'           => $shopOrderCouponExtStatistical->xhs,
                'waiMai'        => [ // 外卖
                    'count' => $shopTakeOutOrderStatistical->all['count'],
                    'sum'   => $shopTakeOutOrderStatistical->all['sum'],
                    'lists' => [
                        'mt'  => $shopTakeOutOrderStatistical->mt,
                        'elm' => $shopTakeOutOrderStatistical->elm,
                        'dy'  => $shopTakeOutOrderStatistical->dy,
                    ],
                ],
                'customPayment' => $shopPayStreamStatistical->customPayment['income'],
                'shopCoupon'    => $shopCouponStatistical->shopCoupon
            ],
            // 敏感操作
            'danger'                       => [
                'foretaste' => [ // 试吃
                    'count' => (int)0,
                    'sum'   => (int)0,
                ],
                'gift'      => $shopOrderDetailStatistical->gift,//赠菜
                'discount'  => $shopOrderDiscountStatistical->discount, // 打折
                'reduce'    => $shopOrderDiscountStatistical->reduce, // 减免
            ],
            // 订单来源
            'source'                       => [
                'pos'             => $shopOrderStatistical->pos, // 收银pos
                'scan'            => $shopOrderStatistical->scan, // 扫码点餐
                'average'         => (int)$shopOrderStatistical->average, // 单均 = 订单实收/订单量
                'averageOriginal' => (int)$shopOrderStatistical->averageOriginal, // 折前的单均
                'monthTotal'      => (int)$monthTotal
                // 月度累计 当月至所选择日期为止的月度累计实付总金额，=堂食+外卖+券包销售的实收=各渠道收款合计
            ],
            'activity'     => [
                // 活动详情
                'inTotal'       => $shopCouponStatistical->shopActivity,
                //自定义支付
                'customPayment' => $shopPayStreamStatistical->customPayment['discount']
            ],
            "giftActivity" => $shopGiftActivityStatistical
        ];


        // 行为 - 主被扫统计
        $activeCount = $activeSum = $passiveCount = $passiveSum = 0;
        foreach ($data['pay']['scanPay']['lists'] as $v) {
            $activeCount  += $v['activeScan']['count'];
            $activeSum    += $v['activeScan']['sum'];
            $passiveCount += $v['passiveScan']['count'];
            $passiveSum   += $v['passiveScan']['sum'];
        }

        $data['pay']['action'] = [
            'active'  => [
                'count' => $activeCount,
                'sum'   => $activeSum,
            ],
            'passive' => [
                'count' => $passiveCount,
                'sum'   => $passiveSum,
            ],
        ];
        return $data;
    }


    /**
     * 券包销售统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @return object
     */
    public static function shopCouponPackageStatistical($shopId, $startTime, $endTime): object
    {
        $shopCouponPackage = CouponPackageOrderModel::query()
                                                    ->with('couponPackageRel')
                                                    ->where('shopId', $shopId)
                                                    ->whereBetween('createdAt', [$startTime, $endTime])
                                                    ->where('payStatus', CouponPackageEnum::PAY_STATUS_ON)
                                                    ->get();

        return (object)[
            'shopCouponPackageSale' => [
                'name'  => '券包销售统计',
                'count' => $shopCouponPackage->count(),
                'sum'   => $shopCouponPackage->sum('shopIncomes'),
                'lists' => $shopCouponPackage->groupBy('couponPackageId')->map(function (Collection $v) {
                    return [
                        'name'  => $v->getIterator()->current()->couponPackageRel->name,
                        'count' => $v->count(),
                        'sum'   => $v->sum('shopIncomes')
                    ];
                })->values()
            ]
        ];
    }


    /**
     * 门店使用代金券统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @return object
     */
    public static function shopCouponStatistical($shopId, $startTime, $endTime): object
    {
        $engine = (new SeparateService($startTime, $endTime))->check();
        if ($engine == SeparateService::DB) {
            $model = OrderCouponSplitModel::suffix($shopId);
        } else {
            $model = OrderCouponCHModel::query();
        }

        $orderCouponLists = $model
            ->whereBetween('createdAt', [$startTime, $endTime])
            ->where('shopId', $shopId)
            ->where('status', OrderCouponSplitModel::STATUS_USED)
            ->select([
                'couponDiscountPrice',
                'couponCostPrice',
                'couponName',
                'couponId',
                'customerCouponId'
            ])
            ->get();

        $couponIds         = $orderCouponLists->pluck('couponId')->toArray();
        $customerCouponIds = $orderCouponLists->pluck('customerCouponId')->toArray();
        $brandId           = ShopService::getShopInfo($shopId)->brandId ?? 0;

//        $shopActivities = ActivityModel::query()
//                                       ->with('activityCouponRel', function ($query) {
//                                           $query->select(['id', 'couponId', 'activityId']);
//                                       })
//                                       ->where(function ($query) use ($shopId) {
//                                           $shopType = Shop::query()->where("id", $shopId)->first()->type;
//                                           $query->whereIn('shopType', [ActivityEnum::SHOP_TYPE_ALL, $shopType])
//                                                 ->orWhereHas('activityShopRel', function ($query) use ($shopId) {
//                                                     $query->where(['shopId' => $shopId]);
//                                                 });
//                                       })
//                                       ->where([
//                                           'brandId' => $brandId
//                                       ])
//                                       ->select(['id', 'name'])
//                                       ->get();


        $customerCoupons = CustomerCouponModel::query()->whereIn("id", $customerCouponIds)->get();

        return (object)[
            'shopCoupon'   => [
                'name'  => '代金券实收',
                'count' => (int)$orderCouponLists->where('couponCostPrice', ">", 0)->count(),
                'sum'   => (int)$orderCouponLists->sum('couponCostPrice'),
                'lists' => $orderCouponLists->groupBy('couponId')->map(function (Collection $v) {
                    return $v->sum('couponCostPrice') > 0 ? [
                        'name'  => $v->getIterator()->current()->couponName,
                        'count' => $v->count(),
                        'sum'   => $v->sum('couponCostPrice')
                    ] : [];
                })->filter()->values()
            ],
            'shopActivity' => [
                'name'  => '店内活动',
                'count' => (int)$orderCouponLists->count(),
                'sum'   => (int)($orderCouponLists->sum('couponDiscountPrice') - (int)$orderCouponLists->sum('couponCostPrice')),
                'lists' => $orderCouponLists->groupBy('couponId')->map(function (Collection $item, $couponId) use (
                    $customerCoupons
                ) {
                    $name = attributeGet(
                        $customerCoupons->where("id", $item->getIterator()->current()->customerCouponId)->first(),
                        "sourceName",
                        attributeGet($item->getIterator()->current(), "couponName", "")
                    );
                    return [
                        'name'  => $name,
                        'count' => $item->count(),
                        'sum'   => (int)($item->sum('couponDiscountPrice') - (int)$item->sum('couponCostPrice'))
                    ];
                })->values()
            ]
        ];
    }


    /**
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @param $normalOrderIds
     * @return object
     */
    public static function shopPayStreamStatistical($shopId, $startTime, $endTime, $normalOrderIds): object
    {
        $engine = (new SeparateService($startTime, $endTime))->check();

        $shopPayStreamStatistical = collect();

        // 防止一次 whereIn太多orderId
        collect($normalOrderIds)->chunk(300)->each(function ($normalOrderEach) use ($shopId, &$shopPayStreamStatistical, $engine) {

            if ($engine == SeparateService::DB) {
                $model = PayStreamModel::suffix($shopId, PayStreamModel::SYS_TYPE_RMS_MEAL);
            } else {
                $model = PayStreamCHModel::query();
            }

            $shopPayStreamStatistical = $shopPayStreamStatistical->merge(
                $model
                    ->whereIn("orderId", $normalOrderEach->values()->toArray())
                    ->where('shopId', $shopId)
                    ->where('sysType', PayStreamModel::SYS_TYPE_RMS_MEAL)
                    ->where('payStatus', PayStreamModel::PAY_STATUS_1)
                    ->select([
                        'isPaidIn',
                        'payPrice',
                        'orderId',
                        'payChannel',
                        'payChannelChild',
                        'payAction',
                        'payNo'
                    ])
                    ->get()
            );
        });

        //退款流水
        $shopRefundStreamStatistical = RefundStreamModel::query()
                                                        ->whereIn('orderId',
                                                            $shopPayStreamStatistical->pluck('orderId')->toArray())
                                                        ->get()
                                                        ->groupBy('payNo')
                                                        ->map(function ($v, $payNo) {
                                                            return [
                                                                'payNo'       => $payNo,
                                                                'refundPrice' => $v->sum('refundPrice')
                                                            ];
                                                        })
                                                        ->pluck('refundPrice', 'payNo');


        //支付流水剔除退款流水
        $shopPayOutRefundStreamStatistical = $shopPayStreamStatistical->map(function ($v) use (
            $shopRefundStreamStatistical
        ) {
            if (isset($shopRefundStreamStatistical[$v->payNo])) {
                $v->payPrice = $v->payPrice - $shopRefundStreamStatistical[$v->payNo];
            }
            return $v;
        })->values()->where('payPrice', '>', 0);

        //现金
        $shopCashPayStreamStatistical = $shopPayOutRefundStreamStatistical->where('payChannel',
            PayStreamModel::PAY_CHANNEL_CASH);

        //自定义支付
        $shopCustomPaymentPayStreamStatistical = $shopPayOutRefundStreamStatistical->where('payChannel', '>',
            PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT);

        return (object)[
            //试吃
            "foretaste"     => $shopCustomPaymentPayStreamStatistical
                ->where('isPaidIn', PayStreamModel::PAID_IN_NO)
                ->where("payChannel", CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK)
                ->sum("payPrice"),
            //首款合计
            'total'         => [
                'count' => (int)$shopPayOutRefundStreamStatistical
                    ->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                    ->groupBy('orderId')
                    ->count(),
                'sum'   => (int)$shopPayOutRefundStreamStatistical
                    ->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                    ->sum('payPrice'),
            ],
            //现金
            'cash'          => [
                'count' => (int)$shopCashPayStreamStatistical->count(),
                'sum'   => (int)$shopCashPayStreamStatistical->sum('payPrice')
            ],
            //自定义支付
            'customPayment' => [
                //计入实收
                'income'   => [
                    'count' => (int)$shopCustomPaymentPayStreamStatistical
                        ->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                        ->count(),
                    'sum'   => (int)$shopCustomPaymentPayStreamStatistical
                        ->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                        ->sum('payPrice'),
                    'lists' => $shopCustomPaymentPayStreamStatistical
                        ->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                        ->groupBy('payChannel')
                        ->map(function (Collection $v) {
                            return [
                                'count' => $v->count(),
                                'sum'   => $v->sum('payPrice'),
                                'name' => CustomPaymentModel::getNameById($v->getIterator()
                                                                            ->current()->payChannel),
                            ];
                        })->values()
                ],
                //计入优惠
                'discount' => [
                    'name'  => '自定义支付(优惠)',
                    'count' => (int)$shopCustomPaymentPayStreamStatistical
                        ->where('isPaidIn', PayStreamModel::PAID_IN_NO)
                        ->count(),
                    'sum'   => (int)$shopCustomPaymentPayStreamStatistical
                        ->where('isPaidIn', PayStreamModel::PAID_IN_NO)
                        ->sum('payPrice'),
                    'lists' => $shopCustomPaymentPayStreamStatistical
                        ->where('isPaidIn', PayStreamModel::PAID_IN_NO)
                        ->groupBy('payChannel')
                        ->map(function (Collection $v) {
                            return [
                                'count' => $v->count(),
                                'sum'   => $v->sum('payPrice'),
                                'name' => CustomPaymentModel::getNameById($v->getIterator()
                                                                            ->current()->payChannel),
                            ];
                        })->values()
                ]
            ],
            //扫码支付
            'scanPay'       => [
                'count' => (int)$shopPayOutRefundStreamStatistical
                    ->whereIn('payChannel', [
                        PayStreamModel::PAY_CHANNEL_ALI,
                        PayStreamModel::PAY_CHANNEL_WX,
                        PayStreamModel::PAY_CHANNEL_FY
                    ])
                    ->groupBy('orderId')
                    ->count(),
                'sum'   => (int)$shopPayOutRefundStreamStatistical
                    ->whereIn('payChannel', [
                        PayStreamModel::PAY_CHANNEL_ALI,
                        PayStreamModel::PAY_CHANNEL_WX,
                        PayStreamModel::PAY_CHANNEL_FY
                    ])
                    ->sum('payPrice'),
                'lists' => [
                    'wxPay'    => [
                        'count'       => (int)$shopPayOutRefundStreamStatistical
                            ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_WX)
                            ->groupBy('orderId')
                            ->count(),
                        'sum'         => (int)$shopPayOutRefundStreamStatistical
                            ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_WX)
                            ->sum('payPrice'),
                        'activeScan'  => [
                            'count' => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_WX)
                                ->whereIn('payAction',
                                    [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI])
                                ->groupBy('orderId')
                                ->count(),
                            'sum'   => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_WX)
                                ->whereIn('payAction',
                                    [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI])
                                ->sum('payPrice'),
                        ],
                        'passiveScan' => [
                            'count' => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_WX)
                                ->where('payAction', PayStreamModel::PAY_ACTION_QRCODE)
                                ->groupBy('orderId')
                                ->count(),
                            'sum'   => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_WX)
                                ->where('payAction', PayStreamModel::PAY_ACTION_QRCODE)
                                ->sum('payPrice'),
                        ]
                    ], // 扫码支付微信
                    'aliPay'   => [
                        'count'       => (int)$shopPayOutRefundStreamStatistical
                            ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_ALI)
                            ->groupBy('orderId')
                            ->count(),
                        'sum'         => (int)$shopPayOutRefundStreamStatistical
                            ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_ALI)
                            ->sum('payPrice'),
                        'activeScan'  => [
                            'count' => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_ALI)
                                ->whereIn('payAction',
                                    [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI])
                                ->groupBy('orderId')
                                ->count(),
                            'sum'   => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_ALI)
                                ->whereIn('payAction',
                                    [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI])
                                ->sum('payPrice'),
                        ],
                        'passiveScan' => [
                            'count' => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_ALI)
                                ->where('payAction', PayStreamModel::PAY_ACTION_QRCODE)
                                ->groupBy('orderId')
                                ->count(),
                            'sum'   => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_ALI)
                                ->where('payAction', PayStreamModel::PAY_ACTION_QRCODE)
                                ->sum('payPrice'),
                        ]
                    ],  // 扫码支付支付宝
                    'unionPay' => [
                        'count'       => (int)$shopPayOutRefundStreamStatistical
                            ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY)
                            ->groupBy('orderId')
                            ->count(),
                        'sum'         => (int)$shopPayOutRefundStreamStatistical
                            ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY)
                            ->sum('payPrice'),
                        'activeScan'  => [
                            'count' => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY)
                                ->whereIn('payAction',
                                    [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI])
                                ->groupBy('orderId')
                                ->count(),
                            'sum'   => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY)
                                ->whereIn('payAction',
                                    [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI])
                                ->sum('payPrice'),
                        ],
                        'passiveScan' => [
                            'count' => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY)
                                ->where('payAction', PayStreamModel::PAY_ACTION_QRCODE)
                                ->groupBy('orderId')
                                ->count(),
                            'sum'   => (int)$shopPayOutRefundStreamStatistical
                                ->where('payChannelChild', PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY)
                                ->where('payAction', PayStreamModel::PAY_ACTION_QRCODE)
                                ->sum('payPrice'),
                        ]
                    ],  // 云闪付
                ]
            ]
        ];
    }

    /**
     * 门店第三方优惠券统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @return object
     */
    public static function shopOrderCouponExtStatistical($shopId, $startTime, $endTime): object
    {
        $engine = (new SeparateService($startTime, $endTime))->check();
        if ($engine == SeparateService::DB) {
            $model = OrderCouponExtSplitModel::suffix($shopId);
        } else {
            $model = OrderCouponExtCHModel::query();
        }

        $shopOrderCouponExt = $model
            ->where("shopId", $shopId)
            ->whereBetween('createdAt', [$startTime, $endTime])
            ->get();

        $shopOrderCouponExtMt = $shopOrderCouponExt
            ->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED)
            ->where('extPlatform', CouponExtEnum::EXT_PLATFORM_MEITUAN);

        $shopOrderCouponExtDy = $shopOrderCouponExt
            ->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED)
            ->where('extPlatform', CouponExtEnum::EXT_PLATFORM_DOUYIN);

        $shopOrderCouponExtXhs = $shopOrderCouponExt
            ->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED)
            ->where('extPlatform', CouponExtEnum::EXT_PLATFORM_XHS);


        return (object)[
            'mt'  => [
                'count'    => (int)$shopOrderCouponExtMt->count(),
                'sum'      => (int)$shopOrderCouponExtMt->sum('couponExtCostPrice'),
                'orderNum' => (int)$shopOrderCouponExtMt->groupBy('orderId')->count(),
                'lists'    => $shopOrderCouponExtMt->groupBy('couponExtSid')->map(function (
                    Collection $item
                ) {
                    return [
                        'name'     => $item->getIterator()->current()->couponExtName,
                        'count'    => (int)$item->count(),
                        'sum'      => (int)$item->sum('couponExtCostPrice'),
                        'orderNum' => (int)$item->groupBy('orderId')->count(),
                    ];
                })->values()->toArray(),
            ],
            'dy'  => [
                'count'    => (int)$shopOrderCouponExtDy->count(),
                'sum'      => (int)$shopOrderCouponExtDy->sum('couponExtCostPrice'),
                'orderNum' => (int)$shopOrderCouponExtDy->groupBy('orderId')->count(),
                'lists'    => $shopOrderCouponExtDy->groupBy('couponExtName')->map(function (
                    Collection $item
                ) {
                    return [
                        'name'     => $item->getIterator()->current()->couponExtName,
                        'count'    => (int)$item->count(),
                        'sum'      => (int)$item->sum('couponExtCostPrice'),
                        'orderNum' => (int)$item->groupBy('orderId')->count(),
                    ];
                })->values()->toArray(),
            ],
            'xhs' => [
                'count'    => (int)$shopOrderCouponExtXhs->count(),
                'sum'      => (int)$shopOrderCouponExtXhs->sum('couponExtCostPrice'),
                'orderNum' => (int)$shopOrderCouponExtXhs->groupBy('orderId')->count(),
                'lists'    => $shopOrderCouponExtXhs->groupBy('couponExtName')->map(function (
                    Collection $item
                ) {
                    return [
                        'name'     => $item->getIterator()->current()->couponExtName,
                        'count'    => (int)$item->count(),
                        'sum'      => (int)$item->sum('couponExtCostPrice'),
                        'orderNum' => (int)$item->groupBy('orderId')->count(),
                    ];
                })->values()->toArray(),
            ]
        ];
    }

    /**
     * 门店外卖订单统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @return object
     */
    public static function shopTakeOutOrderStatistical($shopId, $startTime, $endTime): object
    {
        $engine = (new SeparateService($startTime, $endTime))->check();
        if ($engine == SeparateService::DB) {
            $model = WaiMaiOrderModel::suffix($shopId);
        } else {
            $model = WaiMaiOrderCHModel::query();
        }

        $shopTakeOutOrder = $model
            ->whereBetween('createdAt', [$startTime, $endTime])
            ->where('shopId', $shopId)
            ->where('orderStatus', '!=', WaiMaiDBEnum::ORDER_STATUS_7)
            ->get();

        $shopTakeOutOrderElm = $shopTakeOutOrder->where('sourceType', WaiMaiDBEnum::SOURCE_TYPE_ELM);
        $shopTakeOutOrderMt  = $shopTakeOutOrder->where('sourceType', WaiMaiDBEnum::SOURCE_TYPE_MT_WM);
        $shopTakeOutOrderDy  = $shopTakeOutOrder->where('sourceType', WaiMaiDBEnum::SOURCE_TYPE_DOUYIN_WM);


        return (object)[
            'all' => [
                'name'                     => '外卖营业指标',
                'count'                    => (int)$shopTakeOutOrder->count(),
                //外卖订单量
                'sumOriginalPrice'         => (int)
                ($shopTakeOutOrder->sum('originalPrice') - $shopTakeOutOrder->sum('originalShippingPrice') - $shopTakeOutOrder->sum('packingPrice')),
                //外卖营业额
                'sumOriginalShippingPrice' => (int)$shopTakeOutOrder->sum('originalShippingPrice'),
                //外卖配送费
                'sumPackingPrice'          => (int)$shopTakeOutOrder->sum('packingPrice'),
                //外卖参合费
                'sumDiscount'              => (int)$shopTakeOutOrder->sum('discountPrice'),
                //外卖优惠金额
                'sumRefundPrice'           => (int)0,
                //外卖退款合计
                'sumPayPrice'              => (int)$shopTakeOutOrder->sum('payPrice'),
                //外卖顾客应付金额
                'sum'                      => (int)$shopTakeOutOrder->sum('expectIncome'),
                //外卖营业收入
                'sumActivityExpenditure'   => (int)$shopTakeOutOrder->sum('activityExpenditure'),
                //商家活动支出
                'sumPlatformPrice'         => (int)$shopTakeOutOrder->sum('platformPrice'),
                //平台服务费合计
                'sumOtherPrice'            => (int)$shopTakeOutOrder->sum('otherPrice'),
                //其他支出
            ],
            'elm' => [
                'count'            => (int)$shopTakeOutOrderElm->count(),
                'sum'              => (int)$shopTakeOutOrderElm->sum('expectIncome'),
                'sumPlatformPrice' => (int)$shopTakeOutOrderElm->sum('platformPrice'),
            ],
            'mt'  => [
                'count'            => (int)$shopTakeOutOrderMt->count(),
                'sum'              => (int)$shopTakeOutOrderMt->sum('expectIncome'),
                'sumPlatformPrice' => (int)$shopTakeOutOrderMt->sum('platformPrice'),
            ],
            'dy'  => [
                'count'            => (int)$shopTakeOutOrderDy->count(),
                'sum'              => (int)$shopTakeOutOrderDy->sum('expectIncome'),
                'sumPlatformPrice' => (int)$shopTakeOutOrderDy->sum('platformPrice'),
            ],
        ];

    }

    /**
     * 门店订单统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @return object
     */
    public static function shopOrderStatistical($shopId, $startTime, $endTime): object
    {
        $engine = (new SeparateService($startTime, $endTime))->check();
        if ($engine == SeparateService::DB) {
            $model = OrderSplitModel::suffix($shopId);
        } else {
            $model = OrderCHModel::query();
        }

        $orderInfo = $model
            ->where("shopId", $shopId)
            ->whereBetween('completeTime', [$startTime, $endTime])
            ->where('shopId', $shopId)
            ->get();

        //以支付&未全部退款订单
        $normalOrder = $orderInfo->where('orderStatus', OrderEnum::ORDER_STATUS_FINISHED)
                                 ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL);

        $foretasteOrder = $orderInfo
            ->where('payStatus', CodeEnum::ORDER_PAY_STATUS_PAYED)
            ->where('payChannel', CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK);

        return (object)[
            "normalOrderNums"           => $normalOrder->pluck("orderId")->toArray(),
            'average'                   => $normalOrder->count() > 0 ? floor($normalOrder->sum('realPayPrice') / $normalOrder->count()) : 0,
            'averageOriginal'           => $normalOrder->count() > 0 ? floor($normalOrder->sum('originalPrice') / $normalOrder->count()) : 0,
            'sumOriginalPrice'          => $normalOrder->sum('originalPrice'),
            'sumDiscountPrice'          => $normalOrder->sum('realDiscountPrice'),
            'sumRefundMoney'            => $normalOrder->sum('refundMoney'),
            'sumRealPayMoney'           => $normalOrder->sum('realPayPrice'),
            'sumPayPrice'               => $normalOrder->sum('payPrice'),
            'ct'                        => $normalOrder->count(),
            'sumForetasteDiscountPrice' => $foretasteOrder->sum('realDiscountPrice'),
            'eatInStatistical'          => [
                'name'                      => '堂食营业指标',
                'count'                     => $normalOrder->count(),
                //堂食订单量
                'sumOriginalPrice'          => $normalOrder->sum('originalPrice'),
                //堂食营业额
                'sumDiscountPrice'          => $normalOrder->sum('realDiscountPrice'),
                //堂食优惠金额
                'sumRefundMoney'            => $normalOrder->sum('refundMoney'),
                //堂食退款合计
                'sumPayPrice'               => $normalOrder->sum('payPrice'),
                //堂食顾客应付
                'sumRealPayPrice'           => $normalOrder->sum('realPayPrice'),
                //堂食营业收入
                'channelRealPayPrice'       => $normalOrder->where("distributionId", ">", 0)->sum('realPayPrice'),
                //渠道收入
                'channelDistributionAmount' => $normalOrder->where("distributionId", ">", 0)->sum('distributionAmount'),
                //渠道佣金
            ],
            'pos'                       => [
                'count' => (int)$normalOrder->where('sourceType', CodeEnum::SOURCE_TYPE_POS)->count(),
                'sum'   => (int)($normalOrder
                        ->where('sourceType', CodeEnum::SOURCE_TYPE_POS)
                        ->sum('payPrice') +
                    $normalOrder
                        ->where('sourceType',
                            CodeEnum::SOURCE_TYPE_POS)
                        ->sum('couponCostPrice')),
            ],
            'scan'                      => [
                'count' => (int)$normalOrder->where('sourceType', CodeEnum::SOURCE_TYPE_MINI)->count(),
                'sum'   => (int)($normalOrder->where('sourceType', CodeEnum::SOURCE_TYPE_MINI)
                                             ->sum('payPrice') + $normalOrder->where('sourceType',
                        CodeEnum::SOURCE_TYPE_MINI)->sum('couponCostPrice')),
            ]
        ];
    }


    /**
     * 门店订单详情统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @param $normalOrderNums
     * @return object
     */
    public static function shopOrderDetailStatistical($shopId, $startTime, $endTime, $normalOrderNums): object
    {
        $orderDetailInfo = collect();

        // 防止一次 whereIn太多orderId
        collect($normalOrderNums)->chunk(300)->each(function ($normalOrderNumsEach) use ($shopId, &$orderDetailInfo) {

            $normalOrderNumsEach = $normalOrderNumsEach->values();

            $orderDetailInfo = $orderDetailInfo->merge(
                OrderDetailSplitModel::suffix($shopId)
                                     ->where('shopId', $shopId)
                                     ->whereIn("orderId", $normalOrderNumsEach)
                                     ->select([
                                         'orderId',
                                         'freeNum',
                                         'type',
                                         'originalPrice',
                                         'orderId',
                                         'shopId',
                                         'discountType',
                                         'discountPrice',
                                         'packageDetailId'
                                     ])->get()
            );
        });

        $giftOrderDetail_0 = $orderDetailInfo
            ->where("type", 0)
            ->where("packageDetailId", 0)
            ->where('freeNum', '>', 0);

        $giftOrderDetail_1 = $orderDetailInfo
            ->where("type", 1)
            ->where('freeNum', '>', 0);

        return (object)[
            'gift'              => [ // 赠菜
                'sum'   => (int)($giftOrderDetail_0->sum("originalPrice") + $giftOrderDetail_1->sum("originalPrice")),
                'count' => (int)($giftOrderDetail_0->count() + $giftOrderDetail_1->count()),
            ],
            'childFoodDiscount' => [
                'orderId' => $orderDetailInfo->where('type', 0)
                                             ->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_COUNT)
                                             ->pluck('orderId'),
                'sum'     => (int)$orderDetailInfo->where('type', 0)
                                                  ->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_COUNT)
                                                  ->sum('discountPrice'),
                'count'   => (int)$orderDetailInfo->groupBy('orderId')
                                                  ->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_COUNT)
                                                  ->count(),
            ],
            'childFoodReduce'   => [
                'orderId' => $orderDetailInfo->where('type', 0)
                                             ->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_ANNUL)
                                             ->pluck('orderId'),
                'sum'     => (int)$orderDetailInfo->where('type', 0)
                                                  ->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_ANNUL)
                                                  ->sum('discountPrice'),
                'count'   => (int)$orderDetailInfo->groupBy('orderId')
                                                  ->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_ANNUL)
                                                  ->count(),
            ]
        ];
    }


    /**
     * 门店区间段内折扣统计
     *
     * @param $shopId
     * @param $startTime
     * @param $endTime
     * @param $shopOrderDetailStatistical
     * @return object
     */
    public static function shopOrderDiscountStatistical(
        $shopId,
        $startTime,
        $endTime,
        $shopOrderDetailStatistical,
        $normalOrderIds
    ): object {

        $engine = (new SeparateService($startTime, $endTime))->check();

        $discountInfo = collect();

        // 防止一次 whereIn太多orderId
        collect($normalOrderIds)->chunk(300)->each(function ($normalOrderEach) use ($shopId, &$discountInfo, $engine, $startTime, $endTime) {

            if ($engine == SeparateService::DB) {
                $model = OrderDiscountSplitModel::suffix($shopId);
            } else {
                $model = OrderDiscountCHModel::query();
            }

            //获取订单折扣详情
            $discountInfo = $discountInfo->merge(
                $model
                    ->where("shopId", $shopId)
                    ->whereIn("orderId", $normalOrderEach->values()->toArray())
                    ->whereBetween('createdAt', [$startTime, $endTime])
                    ->select(['discountPrice', 'createdAt', 'discountType', 'orderId'])
                    ->get()
            );
        });

        //折扣集合
        $discountCollection = $discountInfo->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_COUNT);
        //减免集合
        $reduceCollection = $discountInfo->where('discountType', CodeEnum::PRODUCTION_DISCOUNT_TYPE_ANNUL);

        return (object)[

            'discount' => [
                'count' => (int)$discountCollection->pluck('orderId')
                                                   ->merge($shopOrderDetailStatistical->childFoodDiscount['orderId'])
                                                   ->unique()->count(),
                'sum'   => (int)$discountCollection->pluck('discountPrice')
                                                   ->sum() + $shopOrderDetailStatistical->childFoodDiscount['sum']
            ],
            'reduce'   => [
                'count' => (int)$reduceCollection->pluck('orderId')
                                                 ->merge($shopOrderDetailStatistical->childFoodReduce['orderId'])
                                                 ->unique()->count(),
                'sum'   => (int)$reduceCollection->pluck('discountPrice')
                                                 ->sum() + $shopOrderDetailStatistical->childFoodReduce['sum']
            ]

        ];

    }

    /**
     * 获取满赠活动统计数据
     *
     * @param int $shopId
     * @param array $normalOrderNums
     * @return array|null
     */
    public static function shopGiftActivityStatistical(int $shopId, array $normalOrderNums): ?array
    {
        $shopGiftActivity = OrderExternalSplitModel::suffix($shopId)
                                                   ->whereIn("orderId", $normalOrderNums)
                                                   ->where("type", CodeEnum::ORDER_EXTERNAL_TYPE_ACTIVITY)
                                                   ->get();

        $formatGiftActivity = null;
        if ($shopGiftActivity->isNotEmpty()) {
            $activityIds = $shopGiftActivity->pluck("extOrderId")->toArray();
            $formatGiftActivity = ActivityModel::query()
                         ->whereIn("id", $activityIds)
                         ->get()
                         ->map(function (ActivityModel $activityModel) use (
                             $shopGiftActivity
                         ) {
                             return [
                                 "id"    => $activityModel->id,
                                 "name"  => $activityModel->name,
                                 "count" => $shopGiftActivity->where("extOrderId", $activityModel->id)->count()
                             ];
                         })->values()->toArray();
        }

        return $formatGiftActivity;
    }

    public static function sJumpToMiniOrderDetail(string $orderId): string
    {
        // 检查浏览器
        $payChannelChild = BasePay::checkBrowser();
//        $payChannelChild = PayStreamModel::PAY_CHANNEL_CHILD_WX;

        if ($payChannelChild == PayStreamModel::PAY_CHANNEL_CHILD_NULL) {
            throw new PayException(PayCodeEnum::ERR_ALI_WX_BROWSER);
        }

        // 暂时不支持支付宝
        if ($payChannelChild == PayStreamModel::PAY_CHANNEL_CHILD_ALI) {
            throw new PayException(PayCodeEnum::ERR_ALI_WX_BROWSER);
        }

        // 关联到微信小程序，支付订单的url（需要提前配置在小程序后台）
        return config('other.QR_URL') . '/order/' . $orderId;
    }

    /**
     * 校验离线订单 Sign
     *
     * @param $data
     * @return bool
     */
    public static function checkOrderSign($data): bool
    {
        $createAt = $data['createdAt'];
        $sign     = $data['sign'];
        unset($data['sign']);
        return $sign == md5(json_encode($data, 320) . $createAt . '20210717');
    }

    public static function setOrderIdsByUnionid($unionid, $userId, $shopId)
    {
        return OrderSplitModel::suffix($shopId)->query()
                              ->where('platformId', '=', $unionid)
                              ->update(['userId' => $userId]);
    }

    /**
     * 获取订单详情差异总数据
     *
     * @param array $orderDetail
     * @param array $posOrderDetail
     * @return array
     */
    public static function diffOrderDetail(array $orderDetail = [], array $posOrderDetail = []): array
    {
        $orderDetail    = array_column($orderDetail, null, 'id');
        $posOrderDetail = array_column($posOrderDetail, null, 'id');

        $diffValue = [];
        foreach ($posOrderDetail as $posKey => $posValue) {
            if (key_exists($posKey, $orderDetail)) {
                // 判断是否正常
                // 如果要计算 +- 的话 在这里判断
                if (!empty(array_diff($posValue, $orderDetail[$posKey]))) {
                    $diffValue[] = $posValue;
                }
            }

        }
        return $diffValue;
    }

    public static function bOrderList(
        int $brandId,
        int $shopId,
        int $userId,
        string $completeTimeStart = '',
        string $completeTimeEnd = '',
        string $productName = '',
        ?int $serialNum = null,
        string $payChannel = '',
        string $sortBy = '',
        string $sort = '',
        int $pageSize = 20,
        int $pageNum = 1,
        array $sourceInOut = [],
        string $orderId = '',
        $orderStatus = 3
    ): array {

        $engine = (new SeparateService(strtotime($completeTimeStart), strtotime($completeTimeEnd)))->check();
        if ($engine == SeparateService::DB) {
            $model = OrderSplitModel::suffix($shopId);
        } else {
            $model = OrderCHModel::query();
        }

        $query = $model
                                ->where('shopId', $shopId)
//                                ->with('shopRel')
                                ->where('brandId', $brandId)
                                ->when($orderId, function ($query) use ($orderId) {
                                    $query->where('orderId', $orderId);
                                })
                                ->when($serialNum > 0, function ($query) use ($serialNum) {
                                    $query->where('serialNum', $serialNum);
                                })
                                ->when(strlen($payChannel), function ($query) use ($payChannel) {
                                    $query->where('payChannel', $payChannel);
                                })
                                ->when(isset($orderStatus), function ($query) use ($orderStatus) {
                                    $query->where('orderStatus', $orderStatus);
                                })
                                ->when(strlen($productName), function ($query) use ($productName) {
                                    $query->whereHas(
                                        'orderDetailRel',
                                        function ($query) use ($productName) {
                                            $query->where('productName', 'like', "%{$productName}%");
                                        });
                                })
                                ->when(
                                    strlen($completeTimeStart) && strlen($completeTimeEnd),
                                    function ($query) use ($completeTimeStart, $completeTimeEnd) {
                                        $query->whereBetween('completeTime', [
                                            strtotime($completeTimeStart),
                                            strtotime($completeTimeEnd)
                                        ]);
                                    })
                                ->when(
                                    in_array(strtolower($sort), [
                                        'asc',
                                        'desc'
                                    ]) && strlen($sortBy), function ($query) use (
                                    $sort,
                                    $sortBy
                                ) {
                                    $query->orderBy($sortBy, $sort);
                                })
                                ->when(is_array($sourceInOut) && count($sourceInOut),
                                    function ($query) use ($sourceInOut) {
                                        $query->whereIn('sourceType', $sourceInOut);
                                    });

        $totalCount = $query->count();

        $orderPaginator             = (clone $query)
            ->orderBy('createdAt', 'desc')
            ->simplePaginate($pageSize, ['*'], 'pageNum', $pageNum);
        $list                       = $orderPaginator->map(function ($order) {

            $shop = Cache::store('array')->remember('shop:'.$order->shopId, 60, function () use ($order) {
                return Shop::query()->where('id', $order->shopId)->first();
            });

            return [
                'shopId'            => $order->shopId,
                // 店铺id
                'shopCode'          => str_pad((string)optional($shop)->shopCode, 4, '0', STR_PAD_LEFT),
                // 店铺code
                'shopName'          => (string)optional($shop)->name,
                // 店铺名
                'orderId'           => (string)$order->orderId,
                // 18位订单号
                'originalPrice'     => $order->originalPrice,
                //订单原价
                'discountPrice'     => $order->discountPrice,
                //订单优惠
                'shouldPrice'       => $order->shouldPrice,
                // 顾客应付
                'payPrice'          => $order->payPrice,
                //订单实收
                'orderStatus'       => $order->orderStatus,
                'orderStatusText'   => $order->orderStatusText,
                // 订单状态
                'payAction'         => $order->payAction,
                'payActionText'     => $order->payActionText,
                // 结账方式
                'refundStatus'      => $order->refundStatus,
                'refundStatusText'  => $order->refundStatusText,
                // 退款状态
                'refundMoney'       => $order->refundMoney,
                // 退款金额
                'createdBy'         => $order->createdBy,
                // 收银员
                'platformId'        => $order->plantformId,
                'sourceType'        => $order->sourceType,
                'sourceTypeText'    => $order->sourceTypeText,
                'serialNum'         => str_pad($order->serialNum, CodeEnum::ORDER_LEADING_ZERO, "0", STR_PAD_LEFT),
                'completeTime'      => $order->completeTime ? date('Y-m-d H:i:s', $order->completeTime) : '',
                'remark'            => $order->remark,
                'createdAt'         => $order->createdAt,
                'payStatus'         => $order->payStatus,
                'payStatusText'     => $order->payStatusText,
                'payChannel'        => $order->payChannel,
                'payChannelText'    => $order->payChannelText,
                'realPayPrice'      => $order->realPayPrice,//实际支付
                'realDiscountPrice' => $order->realDiscountPrice,//实际优惠
                // 支付方式，暂时不用支持美团券+支付宝
                'divisionBillId'    => (int)$order->divisionBillId, // 分佣的账单 ID
                'brokerage'         => $order->brokerage,//佣金
                'settlePrice'       => $order->realPayPrice - $order->brokerage,//结算金额 订单实收-佣金
            ];
        });

        $querySum = $query
            ->when($engine == SeparateService::DB, function ($query) {
                $query->select(
                    DB::raw('sum(originalPrice) as originalPrice'),
                    DB::raw('sum(realDiscountPrice) as realDiscountPrice'),
                    DB::raw('sum(realPayPrice) as realPayPrice'),
                    DB::raw('sum(refundMoney) as refundMoney'),
                    DB::raw('sum(brokerage) as brokerage'),
                );
            })
            ->when($engine == SeparateService::CLICKHOUSE, function ($query) {
                $query->select(
                    raw('sum(originalPrice) as originalPrice'),
                    raw('sum(realDiscountPrice) as realDiscountPrice'),
                    raw('sum(realPayPrice) as realPayPrice'),
                    raw('sum(refundMoney) as refundMoney'),
                    raw('sum(brokerage) as brokerage'),
                );
            })->get()->first();

        $total['originalPrice']     = $querySum->originalPrice;
        $total['realDiscountPrice'] = $querySum->realDiscountPrice;
        $total['realPayPrice']      = $querySum->realPayPrice;
        $total['refundMoney']       = $querySum->refundMoney;
        $total['brokerage']         = $querySum->brokerage;
        $total['settlePrice']       = $total['realPayPrice'] - $total['brokerage'];//结算金额 订单实收-佣金

        return [
            'count'    => $totalCount,
            'list'     => $list,
            'pageNum'  => $pageNum,
            'pageSize' => $pageSize,
            'total'    => $total,
        ];
    }

    public static function bShortList(
        int $shopId,
        int $completeTimeStartTimestamp = 0,
        int $completeTimeEndTimestamp = 0
    ): array {

        if (!$completeTimeStartTimestamp) {
            $completeTimeStartTimestamp = strtotime(date('y-m-d'));
        }

        if (!$completeTimeEndTimestamp) {
            $completeTimeEndTimestamp = strtotime(date('y-m-d')) + 86399;
        }

        $list = OrderSplitModel::suffix($shopId)
                               ->newQuery()
                               ->where('shopId', $shopId)
                               ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                               ->whereBetween('completeTime', [
                                   $completeTimeStartTimestamp,
                                   $completeTimeEndTimestamp
                               ])
                               ->orderBy('completeTime')
                               ->with(['orderDetailRel'])
                               ->get();

        $list = $list->map(function ($order) {
            return [
                'shopId'       => $order->shopId,
                'orderId'      => (string)$order->orderId,
                'completeTime' => $order->completeTime ? date('Y-m-d H:i:s', $order->completeTime) : '',
                'sourceType'   => $order->sourceType,
            ];
        });

        return [
            'list' => $list
        ];

    }

    /**
     * 订单详情下的套餐明细
     * @param int $orderId
     * @param int $shopId
     * @param int $detailId
     * @return array
     */
    public static function packageProductDetail(int $orderId, int $shopId, int $detailId): array
    {
        $order = OrderSplitModel::suffix($shopId)
                                ->where('orderId', $orderId)
                                ->with('orderDetailRel')
                                ->first();
        if (!$order || !$order->orderDetailRel) {
            return [];
        }

        $products = $order->orderDetailRel->map(function (OrderDetailSplitModel $detail) use (&$index) {
            return [
                'totalDiscountPrice' => $detail->totalDiscountPrice - $detail->couponCostPrice,
                'productId'          => $detail->productId,
                'productName'        => $detail->productName,
                'unit'               => $detail->unit,
                'num'                => $detail->num,
                'originalPrice'      => $detail->originalPrice,
                'discountPrice'      => $detail->discountPrice,
                'payPrice'           => $detail->payPrice + $detail->couponCostPrice,
                'type'               => $detail->type,
                'packageDetailId'    => $detail->packageDetailId,
                'id'                 => (string)$detail->id,
                'packageUnitNum'     => $detail->packageUnitNum,
            ];
        });

        $info['products'] = $products;

        $products = self::filterOrderDetails($info, 'products');
        // 过滤orderDetailId
        $products = collect($products)->where('id', $detailId)->filter()->values()->toArray()[0] ?? [];

        return $products;
    }

    /**
     * 网页后台订单列表，分页
     * @param int $brandId
     * @param int $shopId
     * @param int $userId 用户id
     * @param string $completeTimeStart 格式 2021-09-13 15:19:15
     * @param string $completeTimeEnd 格式 2021-09-13 15:19:15
     * @param string $productName
     * @param int|null $serialNum
     * @param string $payChannel
     * @param string $sortBy 排序字段
     * @param string $sort 排序顺序 asc desc
     * @param int $pageSize
     * @param int $pageNum
     * @return array
     */
    public static function bOrderDetail(int $orderId, int $brandId, int $userId, int $shopId): ?array
    {
        $shopInfo = ShopService::getShopInfo($shopId);

        $db = OrderSplitModel::suffix($shopId)
                             ->where('orderId', $orderId)
                             ->where('brandId', $brandId)
                             ->first();
        if ($db) {
            $engine = SeparateService::DB;
            $model = OrderSplitModel::suffix($shopId);
        } else {
            $engine = SeparateService::CLICKHOUSE;
            $model = OrderCHModel::query();
        }

        $order    = $model
                                   ->where('orderId', $orderId)
                                   ->where('brandId', $brandId)
                                   ->with([
                                       'orderDetailRel'        => function ($query) {
                                           // 按照原价降序排列
                                           $query->orderBy('originalPrice', 'desc')->orderBy('id', 'asc');
                                       },
                                       'customerRel',
                                       'orderOperateRecordRel' => function ($query) {
                                           $query->orderBy('createdAt', 'asc')
                                                 ->orderBy('id', 'asc');
                                       }
                                   ])
                                   ->with([
                                       'orderCouponRel' => function ($query) {
                                           $query->where('customerCouponId', 0);
                                       }
                                   ])
                                   ->with([
                                       'orderExtOneRel' => function ($query) {
                                           $query->select(['orderId', 'extOrderId', 'payPrice']);
                                       }
                                   ])
                                   ->with([
                                       'orderDiscountRel' => function ($query) {
                                           $query->where('discountType', '!=',
                                               CodeEnum::ORDER_DISCOUNT_TYPE_CUSTOM_PAY);
                                       }
                                   ])
                                   ->with([
                                       'orderCouponExtRel' => function ($query) {
                                           $query->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED);
                                       }
                                   ])
                                   ->first();

        if (null === $order) {
            return null;
        }

        $index    = 1;
        $products = $order->orderDetailRel->map(function ($detail) use (&$index) {
            return [
                'index'              => $index++,
                'totalDiscountPrice' => $detail->totalDiscountPrice - $detail->couponCostPrice,
                'productId'          => $detail->productId,
                'productName'        => $detail->productName,
                'unit'               => $detail->unit,
                'num'                => $detail->num,
                'originalPrice'      => $detail->originalPrice,
                'discountPrice'      => $detail->discountPrice,
                'payPrice'           => $detail->payPrice + $detail->couponCostPrice,
                'type'               => $detail->type,
                'packageDetailId'    => $detail->packageDetailId,
                'id'                 => $detail->id,
                'detailId'           => (string)$detail->id,
                'packageUnitNum'     => $detail->packageUnitNum,
            ];
        });
        $logs     = $order->orderOperateRecordRel->map(function (OrderOperateRecordModel $record) {
            return [
                'createdAt'      => $record->createdAt ? date('Y-m-d H:i:s', $record->createdAt) : '',
                'content'        => '',
                'recordTypeText' => $record->recordTypeText,
                'username'       => $record->username,
            ];
        });

        // 查询支付流水
        if ($engine == SeparateService::DB) {
            $model = PayStreamModel::suffix($shopId, PayStreamModel::SYS_TYPE_RMS_MEAL);
        } else {
            $model = PayStreamCHModel::query()->where('shopId', $shopId);
        }

        $payStream = $model
            ->select(['payChannel', 'payNo', 'payPrice', 'isPaidIn', 'payChannelChild'])
            ->where('orderId', $orderId)
            ->where('payStatus', CodeEnum::ORDER_PAY_STATUS_PAYED)
            ->with([
                'streamCustomPaymentRel' => function ($query) {
                    return $query->select(['id', 'name']);
                }
            ])
            ->get();

        $orderNos  = $payStream->pluck('payNo')->toArray();
        //查询券包支付信息
        $packageParPrice = 0;
        if (!empty($order['orderExtOneRel'])) {
            $packageParPrice = $order['orderExtOneRel']['payPrice'];
        }

        //查询退款流水
        $refundField         = [DB::raw("sum(refundPrice) as refundTotalPrice"), 'payNo'];
        $refundStream        = RefundStreamModel::getRefundStreamByPayNos($orderNos, $refundField);
        $refundStreamByPayNo = array_column($refundStream, null, 'payNo');
        $payType             = [];
        $i                   = 0;
        $isReduce            = false;
        if (!empty($payStream)) {
            foreach ($payStream as $value) {
                if ($value['isPaidIn'] == PayStreamModel::PAID_IN_YES) {
                    if ($value['payChannel'] > CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                        $name = "自定义支付：" . (string)optional($value->streamCustomPaymentRel)->name;
                    } elseif ($value['payChannel'] == CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                        $name = '试吃';
                    } else {
                        if ($value['payChannel'] == PayStreamModel::PAY_CHANNEL_FY) {
                            $name = PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$value['payChannelChild']];
                        } else {
                            $name = CodeEnum::CHANNEL_CODE_TEXT[$value['payChannel']];
                        }
                    }
                    if (isset($refundStreamByPayNo[$value['payNo']])) {
                        if ($value['payPrice'] - $refundStreamByPayNo[$value['payNo']]['refundTotalPrice'] > 0) {
                            if ($value['payChannel'] > CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                                $name = "自定义支付：" . (string)optional($value->streamCustomPaymentRel)->name;
                            } elseif ($value['payChannel'] == CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                                $payType[$i]['name'] = '试吃';
                            } elseif ($value['payChannel'] > CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                                $payType[$i]['name'] = CodeEnum::CHANNEL_CODE_TEXT[$value['payChannel']];
                            }
                            $payType[$i]['name']  = $name;
                            $payType[$i]['price'] = $value['payPrice'] - $refundStreamByPayNo[$value['payNo']]['refundTotalPrice'];
                            $i++;
                        }
                    } else {
                        $payType[$i]['name'] = $name;
                        if (!$isReduce) {
                            $payType[$i]['price'] = $value['payPrice'] - $packageParPrice;
                            $isReduce             = true;
                        } else {
                            $payType[$i]['price'] = $value['payPrice'];
                        }
                        $i++;
                    }
                }
            }
        }


        $orderCoupon = $order['orderCouponRel']->toArray();
        if (!empty($orderCoupon)) {
            foreach ($orderCoupon as $value) {
                if ($value['couponCostPrice'] > 0) {
                    $payType[$i]['name']  = $value['couponName'];
                    $payType[$i]['price'] = $value['couponCostPrice'];
                    $i++;
                }
            }
        }
        $orderCouponExt = $order['orderCouponExtRel']->toArray();
        if (!empty($orderCouponExt)) {
            foreach ($orderCouponExt as $value) {
                $payType[$i]['name']  = $value['couponExtName'];
                $payType[$i]['price'] = $value['couponExtCostPrice'];
                $i++;
            }
        }
        //优惠明细
        $orderList           = (new Collection())->push($order);
        $discountRows        = OrderStatisticsService::getInStoreDiscountData($orderList, $shopInfo);
        $orderDiscountDetail = [];
        foreach ($discountRows as $discountRow) {
            array_push($orderDiscountDetail, [
                'discountType'   => $discountRow[3],
                'discountName'   => str_replace('：', '  ', $discountRow[4]),
                'discountAmount' => bcmul($discountRow[6], 100),
            ]);
        }

        // 把优惠券也放到订单优惠里
        if ($engine == SeparateService::DB) {
            $model = OrderCouponSplitModel::suffix($shopId);
        } else {
            $model = OrderCouponCHModel::query()->where('shopId', $shopId);
        }

        $model
            ->where('orderId', $orderId)
            ->where('couponDiscountPrice', '>', 0)
            ->get()
            ->each(function ($item) use (&$orderDiscountDetail) {
                array_push($orderDiscountDetail, [
                    'discountType'   => '优惠券-' . (\App\Kuafu\CustomerCoupon\Enum\CodeEnum::COUPON_TYPE_TEXT[$item['couponType']] ?? ''),
                    'discountName'   => $item['couponName'],
                    'discountAmount' => $item['couponDiscountPrice'],
                ]);
            });

        $info = [
            'orderId'            => (string)$order->orderId,
            'createdAt'          => is_int($order->createdAt) ? date('Y-m-d H:i:s', $order->createdAt) : $order->createdAt->toDateTimeString(),
            'originalPrice'      => $order->originalPrice,
            // 订单原价
            'discountPrice'      => $order->realDiscountPrice,
            // 订单优惠
            'shouldPrice'        => $order->shouldPrice,
            // 应付金额
            'payPrice'           => $order->realPayPrice,
            //订单收入
            'shopName'           => (string)optional($order->shopRel)->name,
            //门店名称
            'shopId'             => $order->shopId,
            'customerPhone'      => (string)optional($order->customerRel)->mobile,
            // 会员手机号码，小程序下单场景会有
            'completeTime'       => $order->completeTime ? date('Y-m-d H:i:s', $order->completeTime) : '',
            // 结账时间
            'sourceType'         => $order->sourceType,
            'sourceTypeText'     => $order->sourceTypeText,
            'remark'             => $order->remark,
            // 整单备注
            'orderStatus'        => $order->orderStatus,
            'orderStatusText'    => $order->orderStatusText,
            // 订单状态
            'serialNum'          => str_pad($order->serialNum, CodeEnum::ORDER_LEADING_ZERO, "0", STR_PAD_LEFT),
            //订单四位流水号
            'createdBy'          => $order->createdBy,
            // 收银员
            'refundStatus'       => $order->refundStatus,
            'refundStatusText'   => $order->refundStatusText,
            // 退款状态
            'refundMoney'        => $order->refundMoney,
            // 退款总金额
            'payChannel'         => $order->payChannel,
            'payChannelText'     => $order->payChannelText,
            // 支付方式，暂时不用支持美团券+支付宝
            'createdUserName'    => (string)optional($order->createdUser)->username,
            'products'           => $products,
            'payType'            => $payType,
            'couponList'         => $orderDiscountDetail,
            'logs'               => $logs,
            'payStatus'          => $order->payStatus,
            'payStatusText'      => CodeEnum::ORDER_PAY_STATUSES[$order->payStatus] ?? '',
            'distributionPer'    => $order->distributionPer,
            'distributionAmount' => $order->distributionAmount,
        ];

        $products            = self::filterOrderDetails($info, 'products');
        $info['products']    = $products;
        $info['productsAgg'] = [ // 菜品数据统计
            'count'           => count($products),
            'sum'             => $payPrice = collect($products)->sum('payPrice'),
            'discount'        => collect($products)->sum('discountPrice'),
            'incomes'         => $payPrice,

            // 新增原始菜品价格计算
            'sumOriginal'     => $originalPrice = collect($products)->sum('originalPrice'),
            'incomesOriginal' => $originalPrice,
        ];
        return $info;
    }

    /**
     * 格式化支付返回的数据格式
     *
     * @param array $payResult
     * @param object | string $orderId
     * @param \Exception|array $errMsg
     * @return array
     */
    public static function payResult(
        $payResult = [],
        $orderResult = [],
        $errMsg = [],
        OrderHandleService $orderHandle = null,
        bool $needQuery = true
    ) {
        if (is_object($errMsg)) {
            $errMsg = self::formatInPayResultException($errMsg);
        }

        $returnData = [
            // 支付返回详情
            'payResult'   => [
                'status'   => $payResult['status'] ?? 0,
                'imageUrl' => $payResult['imageUrl'] ?? '',
            ],
            'orderResult' => [
                'orderId' => (string)($orderResult['orderId'] ?? ''),
            ],
            // 错误信息
            'errMsg'      => [
                'code' => $errMsg['code'] ?? 0,
                'msg'  => $errMsg['msg'] ?? ''
            ],
            // 最新调整的支付返回数据 ↑ 面 数据返回,后面主键融合至 orderInfo 中
            'orderInfo'   => [
                // 主订单详情
                'order'       => [],
                // 订单菜品列表
                'orderDetail' => [],
                // 订单支付列表
                'paymentList' => []
            ],
        ];

        if (!empty($orderHandle)) {
            if ($needQuery) {
                $orderInfo                              = $orderHandle->getOrderPosReturn();
                $returnData['orderInfo']['paymentList'] = $orderInfo['paymentList'] ?? [];
                $returnData['orderInfo']['order']       = $orderInfo['order'] ?? [];
            } else {
                $returnData['orderInfo']['order'] = [
                    'orderId' => $orderHandle->getOrderId() ?? ''
                ];
            }
        }

        Log::channel('order')->info('orderReturn', [
            'returnData' => $returnData
        ]);

        return $returnData;
    }


    /**
     * @param \Exception $errMsg
     * @return array
     */
    public static function formatInPayResultException(\Exception $errMsg): array
    {
        // 订单报错
        return [
            'code' => $errMsg->getCode(),
            'msg'  => $errMsg->getMessage(),
        ];
    }

    /**
     * @param object $order
     * @return array
     */
    public static function formatInPayResultOrderResult(OrderBaseSplitService $order): array
    {

        $orderInfo = $order->getOrderInfo(true);


        return [
            'orderId'     => (string)($orderInfo['orderId'] ?? ''),
            'orderStatus' => $orderResult['orderStatus'] ?? 0,
        ];
    }

    /**
     * 格式化 payResult 中的 couponList
     *
     * @param array $couponList
     * @return array
     */
    public static function formatPayResultExtCouponList(array $couponList): array
    {
        $result = [];

        if (!empty($couponList)) {
            foreach ($couponList as $list) {
                $result[] = [
                    'id'                         => $list['id'],
                    'couponExtName'              => $list['couponExtName'],
                    'couponExtDiscountPrice'     => $list['couponExtDiscountPrice'],
                    'couponExtRealDiscountPrice' => $list['couponExtDiscountPrice'] - $list['couponExtCostPrice'],
                    'couponExtCode'              => $list['couponExtCode'],
                    'couponExtCreatedAt'         => $list['createdAt']
                ];
            }
        }

        return $result;
    }

    /**
     * 生成流水号
     * @param int $shopId
     * @return mixed
     */
    public static function genSerialNum($shopId): int
    {
        $key = 'serialNum_' . date('Ymd');
        $num = Redis::hincrby($key, $shopId, 1);
        Redis::expire($key, 86400);
        return 100 + $num;
    }

    /**
     * 格式化 请求入参数据
     *
     * @param array $data
     * @return array
     * @throws OrderException
     */
    public static function getOrderFormatPostData($data = [])
    {
        if (!empty($data['isAutoCoupon']) && $data['isAutoCoupon'] == true) {
            $isAutoCoupon = true;
        } else {
            $isAutoCoupon = false;
        }

        if (isset($data["deliveryType"]) && !is_int($data["deliveryType"])) {
            throw new OrderException(OrderCodeEnum::ERR_ORDER_PARAM_VALID);
        }

        return [
            //订单 Id
            'orderId'             => $data['orderId'] ?? '',
            // 订单详情
            'detail'              => $data['detail'] ?? [],
            // 订单来源
            'sourceType'          => $data['sourceType'] ?? 0,
            // 用户 优惠券列表
            'couponList'          => $data['couponList'] ?? [],
            // 订单备注
            'remark'              => $data['remark'] ?? '',
            // 传入的订单总价
            'totalPrice'          => $data['totalPrice'] ?? [],
            // 传入的订单折扣/优惠券
            'discount'            => $data['discount'] ?? [],
            /**
             * 传入的三方优惠券
             * 为了 兼容 pos 减少 传入字段
             * type 类型 定义 ※代表已用的
             * 1:系统自己的优惠券  ※2:美团优惠券  3:非自定义支付、4:自定义支付 ※5:抖音优惠券
             */
            'extCoupon'           => $data['extCoupon'] ?? [],
            // 传入的需要退的三方优惠券
            'refundCoupon'        => $data['refundCoupon'] ?? [],
            // POS 端传入的优惠券列表
            'posCouponList'       => $data['posCouponList'] ?? [],
            // 需要撤销的 POS 端传入的优惠券列表
            'refundPosCouponList' => $data['refundPosCouponList'] ?? [],
            // 是否自动使用优惠券
            'isAutoCoupon'        => $isAutoCoupon,
            // 券包 ID
            'couponPackageId'     => $data['couponPackageId'] ?? 0,
            // 勾选的匿名券信息
            'anonymousCouponList' => $data['anonymousCouponList'] ?? [],
            // 支付方式
            'payMethod'           => $data['payMethod'] ?? '',
            // 支付方式 list
            'payMethodList'       => $data['payMethodList'] ?? [],
            // 支付条形码
            'payAuthCode'         => $data['payAuthCode'] ?? '',
            // 需要撤销的的自定义支付列表
            'refundPayMethodList' => $data['refundPayMethodList'] ?? [],
            // 是否开票
            'isInvoice'           => $data['isInvoice'] ?? 0,
            // 请求场景 - 默认为 下单场景
            'orderEvent'          => CodeEnum::ORDER_PAY_EVENT_ORDER,
            // 是否商户自配送 - 后期 废弃这个字段
            'isSelfDelivery'      => $data['isSelfDelivery'] ?? 0,
            // 配送类型
            'deliveryType'        => $data['deliveryType'] ?? 0, // 配送类型0无 1 自配送 2 渠道配送
            // 自配送地址
            'deliveryAddress'     => $data['deliveryAddress'] ?? [],
        ];
    }

    public static function addCouponSourceType($data, $couponSource)
    {
        return array_map(function ($cou) use ($couponSource) {
            return array_map(function ($coupon) use ($couponSource) {
                $coupon['couponSource'] = $couponSource;
                return $coupon;
            }, $cou);
        }, $data);
    }

    /**
     * 二维数组根据某个字段排序
     * @param array $array 要排序的数组
     * @param string $keys 要排序的键字段
     * @param string $sort 排序类型  SORT_ASC     SORT_DESC
     * @return array 排序后的数组
     */
    public static function arraySort(array $array, string $keys, $sort = SORT_DESC): array
    {
        $keysValue = [];
        foreach ($array as $k => $v) {
            $keysValue[$k] = $v[$keys];
        }
        array_multisort($keysValue, $sort, $array);
        return $array;
    }

}
